{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "98cbe3b5-c41b-437a-a888-ef79da152dc0",
   "metadata": {},
   "source": [
    "### Generating Guides from OpenAPI Specification\n",
    "\n",
    "*iteratively create more complicated examples to prototype generation of high quality guides*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e2a11448",
   "metadata": {},
   "source": [
    "### 1️⃣ Rudimentary Example\n",
    "\n",
    "```mermaid\n",
    "graph LR\n",
    "    alloy.com.yaml --> DocumentLoader\n",
    "    DocumentLoader --> Chat\n",
    "    Query[How do I create a journey in Python?] --> Chat\n",
    "    Chat --> Guide\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0d847e21-dc39-4188-8614-e1e6ebfae247",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey in Python using the Alloy API, you'll need to make an HTTP POST request to the appropriate endpoint with the necessary headers and JSON body. Below is an example of how you can do this using the `requests` library in Python.\n",
       "\n",
       "First, ensure you have the `requests` library installed. If not, you can install it using pip:\n",
       "\n",
       "```bash\n",
       "pip install requests\n",
       "```\n",
       "\n",
       "Here's a Python script to create a journey:\n",
       "\n",
       "```python\n",
       "import requests\n",
       "import json\n",
       "\n",
       "# Define the API endpoint\n",
       "url = \"https://demo-qasandbox.alloy.co/v1/journeys\"\n",
       "\n",
       "# Specify your API credentials\n",
       "application_token = \"your_application_token\"\n",
       "application_secret = \"your_application_secret\"\n",
       "\n",
       "# Encode your credentials in base64 format for Basic Auth\n",
       "import base64\n",
       "credentials = f\"{application_token}:{application_secret}\"\n",
       "encoded_credentials = base64.b64encode(credentials.encode(\"utf-8\")).decode(\"utf-8\")\n",
       "\n",
       "# Set up the headers\n",
       "headers = {\n",
       "    \"Authorization\": f\"Basic {encoded_credentials}\",\n",
       "    \"Content-Type\": \"application/json\"\n",
       "}\n",
       "\n",
       "# Define the JSON body of the request\n",
       "data = {\n",
       "    \"entities\": [\n",
       "        {\n",
       "            \"external_entity_id\": \"entity-123\",\n",
       "            \"data\": {\n",
       "                \"name_first\": \"John\",\n",
       "                \"name_last\": \"Doe\",\n",
       "                \"birth_date\": \"1990-01-25\",\n",
       "                \"document_ssn\": \"123-45-6789\",\n",
       "                \"addresses\": [\n",
       "                    {\n",
       "                        \"type\": \"primary\",\n",
       "                        \"line_1\": \"123 Main St\",\n",
       "                        \"city\": \"Anytown\",\n",
       "                        \"state\": \"CA\",\n",
       "                        \"postal_code\": \"12345\",\n",
       "                        \"country_code\": \"US\"\n",
       "                    }\n",
       "                ],\n",
       "                \"emails\": [\n",
       "                    {\n",
       "                        \"email_address\": \"john.doe@example.com\"\n",
       "                    }\n",
       "                ],\n",
       "                \"phones\": [\n",
       "                    {\n",
       "                        \"phone_number\": \"555-1234\"\n",
       "                    }\n",
       "                ]\n",
       "            },\n",
       "            \"entity_type\": \"person\",\n",
       "            \"branch_name\": \"default\"\n",
       "        }\n",
       "    ]\n",
       "}\n",
       "\n",
       "# Make the POST request\n",
       "response = requests.post(url, headers=headers, data=json.dumps(data))\n",
       "\n",
       "# Check the response\n",
       "if response.status_code == 201:\n",
       "    print(\"Journey created successfully.\")\n",
       "    print(response.json())\n",
       "else:\n",
       "    print(\"Failed to create journey.\")\n",
       "    print(response.text)\n",
       "```\n",
       "\n",
       "### Explanation:\n",
       "1. **URL and Headers**: The URL points to the journey creation endpoint. The headers include authorization (using Basic Auth with your application token and secret) and content type set to `application/json`.\n",
       "\n",
       "2. **Data**: The JSON body contains the details of the entities involved in the journey. Adjust the fields according to the specific requirements of your workflow.\n",
       "\n",
       "3. **Request**: The `requests.post` method is used to send the POST request with the specified URL, headers, and JSON data.\n",
       "\n",
       "4. **Response Handling**: The script checks if the response status code is 201 (Created), indicating success. It then prints the JSON response or error message.\n",
       "\n",
       "Make sure to replace `\"your_application_token\"` and `\"your_application_secret\"` with your actual Alloy API credentials. Adjust the entity details and other parameters as per your specific use case."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
    "from langchain.chains.combine_documents import create_stuff_documents_chain\n",
    "\n",
    "\n",
    "chat = ChatOpenAI(model=\"gpt-4-turbo\", temperature=0.2)\n",
    "question_answering_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"When answering questions, use markdown to ensure code blocks and commands are propertly formatted. Answer the user's questions based on the below context:\\n\\n{context}\",\n",
    "        ),\n",
    "        MessagesPlaceholder(variable_name=\"messages\"),\n",
    "    ]\n",
    ")\n",
    "document_chain = create_stuff_documents_chain(chat, question_answering_prompt)\n",
    "from langchain.document_loaders.text import TextLoader\n",
    "\n",
    "file_path = 'alloy.com.yaml'\n",
    "loader = TextLoader(file_path)\n",
    "docs = loader.load()\n",
    "from langchain.memory import ChatMessageHistory\n",
    "\n",
    "demo_ephemeral_chat_history = ChatMessageHistory()\n",
    "\n",
    "demo_ephemeral_chat_history.add_user_message(\"How do I create a journey in Python?\")\n",
    "\n",
    "output = document_chain.invoke(\n",
    "    {\n",
    "        \"messages\": demo_ephemeral_chat_history.messages,\n",
    "        \"context\": docs,\n",
    "    }\n",
    ")\n",
    "from IPython.display import display, Markdown\n",
    "\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a840e3d0-6810-4461-9892-08cb43b0aec8",
   "metadata": {},
   "source": [
    "### gpt-4-turbo Pricing\n",
    "\n",
    "- Input: $10.00 / 1M tokens\n",
    "\n",
    "- Output: $30.00 / 1M tokens\n",
    "\n",
    "### gpt-3.5-turbo Pricing\n",
    "\n",
    "- Input: $0.50 / 1M tokens\n",
    "\n",
    "- Output: $1.50 / 1M tokens"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "802f69bc-08f2-47e1-80e1-413b1ba9fb2b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "gpt-4-turbo: Price of passing in alloy.com.yaml 1 time: $0.50122\n",
      "gpt-4-turbo: Price of passing in alloy.com.yaml 20 times: $10.0244\n",
      "gpt-3.5-turbo: Price of passing in alloy.com.yaml 1 time: $0.025061\n",
      "gpt-3.5-turbo: Price of passing in alloy.com.yaml 20 times: $0.50122\n"
     ]
    }
   ],
   "source": [
    "import tiktoken\n",
    "\n",
    "# To get the tokeniser corresponding to a specific model in the OpenAI API:\n",
    "enc = tiktoken.encoding_for_model(\"gpt-4\")\n",
    "\n",
    "with open(\"alloy.com.yaml\") as f:\n",
    "    doc = f.read()\n",
    "\n",
    "tokens = enc.encode(doc)\n",
    "len(tokens)\n",
    "gpt4_price = len(tokens) * 10 / 1_000_000\n",
    "gpt35_price = len(tokens) * 0.5 / 1_000_000\n",
    "print(\"gpt-4-turbo: Price of passing in alloy.com.yaml 1 time: ${}\".format(gpt4_price))\n",
    "print(\"gpt-4-turbo: Price of passing in alloy.com.yaml 20 times: ${}\".format(gpt4_price * 20))\n",
    "print(\"gpt-3.5-turbo: Price of passing in alloy.com.yaml 1 time: ${}\".format(gpt35_price))\n",
    "print(\"gpt-3.5-turbo: Price of passing in alloy.com.yaml 20 times: ${}\".format(gpt35_price * 20))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18ab486a-faba-4e7b-91b4-36f3a50bcc52",
   "metadata": {},
   "source": [
    "### ⛔️ Problem #1: Passing entire OpenAPI Specification is too expensive\n",
    "### ⛔️ Problem #2: Entire OpenAPI Specification does not fit in gpt-3.5-turbo\n",
    "### 🤔 Solution: Chunk the OpenAPI Specification, retrieve from vector store, and pass in as context instead\n",
    "\n",
    "#### Data Pipeline\n",
    "\n",
    "```mermaid\n",
    "graph LR\n",
    "    alloy.com.yaml --> Chunk1\n",
    "    alloy.com.yaml --> Chunk2\n",
    "    alloy.com.yaml --> Chunk3\n",
    "    Chunk1 -->|embed| VectorStore\n",
    "    Chunk2 -->|embed| VectorStore\n",
    "    Chunk3 -->|embed| VectorStore\n",
    "    VectorStore -->|How do I create a journey in Python?| Chunk1Out[Chunk1]\n",
    "    VectorStore -->|How do I create a journey in Python?| Chunk3Out[Chunk3]\n",
    "    Chunk1Out --> Context\n",
    "    Chunk3Out --> Context\n",
    "    Context --> Chat\n",
    "    Query[How do I create a journey in Python?] --> Chat\n",
    "    Chat --> Guide\n",
    "```\n",
    "\n",
    "#### RAG Chain\n",
    "\n",
    "```mermaid\n",
    "graph LR\n",
    "    alloy.com.yaml --> TextSplitter\n",
    "    TextSplitter --> Chroma[Chroma 'Vector Store']\n",
    "    Chroma --> Retriever\n",
    "    Retriever --> Context\n",
    "    Context --> Chat\n",
    "    Query[How do I create a journey in Python?] --> Chat\n",
    "    Chat --> Guide\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "6cbdeb3a",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "chat = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0, model_kwargs={\"seed\": 0})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "623d30be-adaa-4671-9334-75e3b4495dc8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.document_loaders.text import TextLoader\n",
    "def init_docs():\n",
    "    file_path = 'alloy.com.yaml'\n",
    "    loader = TextLoader(file_path)\n",
    "    docs = loader.load()\n",
    "    return docs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0a81101f-7a0e-4222-a088-0a3fd09a564f",
   "metadata": {},
   "outputs": [],
   "source": [
    "docs = init_docs()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "af946b79-f6ce-4304-b771-653abba6f0d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_chroma import Chroma\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "\n",
    "# store OAS in vector DB\n",
    "text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)\n",
    "splits = text_splitter.split_documents(docs)\n",
    "vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())\n",
    "\n",
    "# Retrieve and generate using the relevant snippets of the blog.\n",
    "retriever = vectorstore.as_retriever()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "1ed92928-1dee-4758-b76e-7ac072a48a9d",
   "metadata": {},
   "outputs": [],
   "source": [
    "query = \"How do I create a journey in Python?\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "7ed8ff09-de3d-440d-8bc4-19993c6b4a28",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "\n",
    "prompt = hub.pull(\"rlm/rag-prompt\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "8a4efa9c-c3d2-4dbe-85b6-63f38db462cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.runnables import RunnablePassthrough\n",
    "\n",
    "def format_docs(docs):\n",
    "    return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
    "\n",
    "rag_chain = (\n",
    "    {\"context\": retriever | format_docs, \"question\": RunnablePassthrough()}\n",
    "    | prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")\n",
    "\n",
    "output = rag_chain.invoke(query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "0187cf3f-bc8e-49c7-9acc-f412b0e57ed2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey in Python, you would need to define the journey properties such as journey_name, journey_type, journey_token, and journey_version_num. You can then use the provided endpoints to interact with the journey, such as creating applications or adding notes to applications. Additionally, you can create batches of journeys using the specified parameters and workflows."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3783ce2-2944-4d4e-8824-05920350eb20",
   "metadata": {},
   "source": [
    "### 👎 Results \n",
    "\n",
    "Output is nearly useless. Does not provide environment setup instructions or example code.\n",
    "\n",
    "### 🤔 Maybe provide system instructions that are more explicit?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "a77dbfde-760f-4c82-8b34-9b0398520e40",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "better_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"You are an assistant for question-answering tasks. f you don't know the answer, just say that you don't know. Use markdown to ensure code blocks and commands are propertly formatted. Make sure to always include environment setup instructions and code blocks that are helpful for a developer to copy-paste. Always explain inputs and outputs of API requests. Be as detailed as possible. Answer the user's questions based on the below context:\\n\\n{context}\",\n",
    "        ),\n",
    "        (\n",
    "            \"user\",\n",
    "            \"{question}\"\n",
    "        )\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "89986602-059e-4810-a1af-a8b31afab611",
   "metadata": {},
   "outputs": [],
   "source": [
    "rag_chain = (\n",
    "    {\"context\": retriever | format_docs, \"question\": RunnablePassthrough()}\n",
    "    | better_prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "f7081e64-b288-4954-835e-9ad74dea6240",
   "metadata": {},
   "outputs": [],
   "source": [
    "output = rag_chain.invoke(query)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "363d38b4-6e61-461d-b002-4ab74974106b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey in Python, you typically need to make an API request to the endpoint that allows you to create a journey. Below are the general steps to create a journey using Python:\n",
       "\n",
       "1. **Import necessary libraries**: You will need the `requests` library to make API requests.\n",
       "\n",
       "```python\n",
       "import requests\n",
       "```\n",
       "\n",
       "2. **Set up the base URL and authentication**: You need to have the base URL of the API and any authentication tokens required to access the API.\n",
       "\n",
       "```python\n",
       "base_url = \"https://api.example.com\"\n",
       "headers = {\n",
       "    \"Authorization\": \"Bearer YOUR_ACCESS_TOKEN\",\n",
       "    \"Content-Type\": \"application/json\"\n",
       "}\n",
       "```\n",
       "\n",
       "3. **Prepare the payload**: You need to prepare the data that you want to send in the API request. This data should follow the structure expected by the API.\n",
       "\n",
       "```python\n",
       "payload = {\n",
       "    \"journey_name\": \"My New Journey\",\n",
       "    \"journey_type\": \"application\",\n",
       "    \"journey_version_num\": \"1.0\",\n",
       "    # Add any other required fields for the journey\n",
       "}\n",
       "```\n",
       "\n",
       "4. **Make the API request to create the journey**:\n",
       "\n",
       "```python\n",
       "response = requests.post(f\"{base_url}/journeys\", headers=headers, json=payload)\n",
       "\n",
       "if response.status_code == 201:\n",
       "    print(\"Journey created successfully\")\n",
       "    journey_data = response.json()\n",
       "    journey_token = journey_data[\"journey_token\"]\n",
       "else:\n",
       "    print(\"Failed to create journey. Status code:\", response.status_code)\n",
       "```\n",
       "\n",
       "5. **Handle the response**: Check the response status code to ensure the journey was created successfully. If successful, you can extract the `journey_token` from the response for future reference.\n",
       "\n",
       "Please note that the actual implementation may vary based on the specific API you are using. Make sure to refer to the API documentation for the exact endpoint, payload structure, and any additional parameters required for creating a journey."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a400e30-2d3c-4cb8-969e-c395e1178d4d",
   "metadata": {},
   "source": [
    "### 👎 Results\n",
    "\n",
    "Looks like the result is lacking the correct base URL, proper parameters, and explanation of inputs and outputs. This makes the answer still nearly useless. Likely because the model was not given enough context.\n",
    "\n",
    "### 🤔 Lets investigate what our vector store is returning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "3dc37441-1375-4f19-8975-9e9f1840fd60",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "type: object\n",
      "                                  properties:\n",
      "                                    href:\n",
      "                                      type: string\n",
      "                      journey:\n",
      "                        type: object\n",
      "                        properties:\n",
      "                          journey_name:\n",
      "                            type: string\n",
      "                          journey_type:\n",
      "                            type: string\n",
      "                            enum:\n",
      "                              - application\n",
      "                              - alert\n",
      "                          journey_token:\n",
      "                            type: string\n",
      "                          journey_version_num:\n",
      "                            type: string\n",
      "                          _links:\n",
      "                            type: object\n",
      "                            properties:\n",
      "                              self:\n",
      "                                type: object\n",
      "                                properties:\n",
      "properties:\n",
      "                          self:\n",
      "                            type: object\n",
      "                            properties:\n",
      "                              journey_batch:\n",
      "                                type: object\n",
      "                                properties:\n",
      "                                  href:\n",
      "                                    description: Link to batch journey applications\n",
      "                                    type: string\n",
      "                      _embedded:\n",
      "                        type: object\n",
      "                        properties:\n",
      "                          journey_applications:\n",
      "                            type: array\n",
      "                            items:\n",
      "                              type: object\n",
      "                              properties:\n",
      "                                journey_application_token:\n",
      "                                  type: string\n",
      "                                sandbox:\n",
      "                                  type: boolean\n",
      "type: string\n",
      "                      page:\n",
      "                        type: number\n",
      "                        default: 1\n",
      "                        description: Default is 1\n",
      "                      per_page:\n",
      "                        type: number\n",
      "                        default: 1000\n",
      "                        description: Default/maximum is 1000\n",
      "  /journeys/{journey_token}/applications/{journey_application_token}/notes:\n",
      "    post:\n",
      "      parameters:\n",
      "        - in: path\n",
      "          name: journey_token\n",
      "          required: true\n",
      "          description: Identifier of the journey\n",
      "          schema:\n",
      "            type: string\n",
      "            example: J-VCQoADBJxeHtmdAvFqoS\n",
      "        - in: path\n",
      "          name: journey_application_token\n",
      "          required: true\n",
      "          description: Token associated with your Journey Application\n",
      "          schema:\n",
      "            type: string\n",
      "            example: JA-mhjlfS6nZe1G6HuvAKVq\n",
      "      tags:\n",
      "        - Journeys\n",
      "type: object\n",
      "                            properties:\n",
      "                              workflow_name:\n",
      "                                type: string\n",
      "                              parameters:\n",
      "                                type: object\n",
      "                                properties:\n",
      "                                  required:\n",
      "                                    type: array\n",
      "                                    items:\n",
      "                                      type: object\n",
      "                                  optional:\n",
      "                                    type: array\n",
      "                                    items:\n",
      "                                      type: object\n",
      "                                  or:\n",
      "                                    type: array\n",
      "                                    items:\n",
      "                                      type: object\n",
      "  /journeys/{journey_token}/batches:\n",
      "    post:\n",
      "      parameters:\n",
      "        - in: path\n",
      "          name: journey_token\n",
      "          required: true\n"
     ]
    }
   ],
   "source": [
    "results = retriever.invoke(query)\n",
    "\n",
    "for doc in results:\n",
    "    print(doc.page_content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26ee338e-8354-4acb-8e23-a1b61d459eb2",
   "metadata": {},
   "source": [
    "### 👎 Useless chunk results\n",
    "\n",
    "The results don't contain anything about the relevant API endpoint\n",
    "\n",
    "### 🤔 Can we improve the chunk results by doing smarter chunking?\n",
    "\n",
    "Maybe if we chunk the OpenAPI spec based on operations, we can give the LLM better context. For smarter chunking, we can try to chunk the OpenAPI into documents that only contain relevant information for a specific operation but keep all the contextual information (everything besides `paths`)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "def18e15-12ef-4b74-b812-6bf8957ab0b3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "72\n"
     ]
    }
   ],
   "source": [
    "import yaml\n",
    "import jsonref\n",
    "from jsonref import replace_refs\n",
    "from langchain_core.documents.base import Document\n",
    "from copy import deepcopy\n",
    "from pprint import pprint\n",
    "\n",
    "with open(\"alloy.com.yaml\") as f:\n",
    "    spec = f.read()\n",
    "\n",
    "def chunk_openapi_by_operation(openapi: str):\n",
    "    parsed = yaml.safe_load(openapi)\n",
    "\n",
    "    operations: (str, str) = []\n",
    "    # 1) list all operations by (path, HTTP method)\n",
    "    for path, methods in parsed['paths'].items():\n",
    "        for method in methods.keys():\n",
    "            # if method is not an HTTP method then skip\n",
    "            if method.lower() not in ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace']:\n",
    "                continue\n",
    "            operations.append((path, method))\n",
    "\n",
    "    # 2) create a chunk for every operation\n",
    "\n",
    "    # 2.a) Dereference entire OpenAPI Spec\n",
    "    dereferenced = replace_refs(parsed, lazy_load=False)\n",
    "\n",
    "    chunks = []\n",
    "    for operation in operations:\n",
    "        path = operation[0]\n",
    "        method = operation[1]\n",
    "        chunk = deepcopy(dereferenced)\n",
    "        if 'tags' in chunk['paths'][operation[0]][operation[1]]:\n",
    "            tags = chunk['paths'][operation[0]][operation[1]]['tags']\n",
    "\n",
    "        # first tag if possible\n",
    "        if tags:\n",
    "            tag_name = tags[0]\n",
    "\n",
    "        # delete all tags on OAS except tag for this operation\n",
    "        while len(chunk['tags']) > 1:\n",
    "            for i in range(len(chunk['tags']) - 1, -1, -1):\n",
    "                if chunk['tags'][i]['name'] != tag_name:\n",
    "                    chunk['tags'].pop(i)\n",
    "\n",
    "        if \"summary\" in chunk['paths'][path][method]:\n",
    "            summary = chunk['paths'][path][method]['summary']\n",
    "        else:\n",
    "            summary = \"\"\n",
    "\n",
    "        if \"description\" in chunk['paths'][path][method]:\n",
    "            description = chunk['paths'][path][method]['description']\n",
    "        else:\n",
    "            description = \"\"\n",
    "\n",
    "        # delete other operations\n",
    "        for other_operation in operations:\n",
    "            if other_operation[0] == operation[0]:\n",
    "                continue\n",
    "            if other_operation[0] in chunk['paths']:\n",
    "                del chunk['paths'][other_operation[0]]\n",
    "\n",
    "        # delete empty paths\n",
    "        for path in chunk['paths'].keys():\n",
    "            if not chunk['paths'][path]:\n",
    "                del chunk['paths'][path]\n",
    "\n",
    "        # delete other operations under same path\n",
    "        keys = list(chunk['paths'][operation[0]].keys())\n",
    "        for method in keys:\n",
    "            if operation[1] == method:\n",
    "                continue\n",
    "            del chunk['paths'][operation[0]][method]\n",
    "\n",
    "        # delete all components (should be inlined from 2.a)\n",
    "        del chunk['components']\n",
    "        chunks.append(({\n",
    "            \"path\": operation[0],\n",
    "            \"method\": operation[1],\n",
    "            \"openapi\": yaml.dump(chunk),\n",
    "            \"tag\": tag_name,\n",
    "            \"summary\": summary,\n",
    "            \"description\": description\n",
    "        }))\n",
    "    return list(map(lambda chunk: Document(page_content=chunk[\"openapi\"], metadata={\n",
    "        \"path\": chunk[\"path\"],\n",
    "        \"method\": chunk[\"method\"],\n",
    "        \"tag\": chunk[\"tag\"],\n",
    "        \"summary\": chunk[\"summary\"],\n",
    "        \"description\": chunk[\"description\"]\n",
    "    }), chunks))\n",
    "chunks = chunk_openapi_by_operation(spec)\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "print(len(chunks))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "b227bc82-8edc-4564-951b-1fcbd503b4ac",
   "metadata": {},
   "outputs": [],
   "source": [
    "# reset chroma DB\n",
    "from langchain_community.vectorstores.chroma import Chroma\n",
    "\n",
    "Chroma().delete_collection()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "fe0629ac-7535-4c67-886b-66774590e71c",
   "metadata": {
    "vscode": {
     "languageId": "plaintext"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.chains.query_constructor.base import AttributeInfo\n",
    "from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
    "from langchain_community.vectorstores.chroma import Chroma\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "import os\n",
    "\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "\n",
    "query = \"How do I create a journey application in Python?\"\n",
    "\n",
    "chat = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0, model_kwargs={\"seed\": 0})\n",
    "\n",
    "# Reset the collection to remove embeddings from previous runs\n",
    "# text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)\n",
    "# splits = text_splitter.split_documents(chunks)\n",
    "vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "e8dc21d4-1a28-4e6c-8191-0f0a2eeb8066",
   "metadata": {},
   "outputs": [],
   "source": [
    "metadata_field_info = [\n",
    "    AttributeInfo(\n",
    "        name=\"path\",\n",
    "        description=\"The subpath for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"method\",\n",
    "        description=\"The HTTP Method for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"tag\",\n",
    "        description=\"The logical grouping for this API operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"summary\",\n",
    "        description=\"A short description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"description\",\n",
    "        description=\"A more detailed description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "]\n",
    "document_content_description = \"The pruned OpenAPI specification which includes only the relevant information for a particular operation in the OpenAPI specification.\"\n",
    "\n",
    "# Dylan: really stupid, but I had to upgrade langchain to get this to work for some reason\n",
    "retriever = SelfQueryRetriever.from_llm(\n",
    "    chat, vectorstore, document_content_description, metadata_field_info, verbose=True, search_kwargs={\"k\": 4}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "3d66cf91-1aa8-4ba5-a9c5-6bda0809bf7c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'description': 'Create a journey application for one or more entities.\\n',\n",
      "  'method': 'post',\n",
      "  'path': '/journeys/{journey_token}/applications',\n",
      "  'summary': 'Create Journey Application',\n",
      "  'tag': 'Journeys'},\n",
      " {'description': 'Create a note associated with the specified Journey '\n",
      "                 'Application',\n",
      "  'method': 'post',\n",
      "  'path': '/journeys/{journey_token}/applications/{journey_application_token}/notes',\n",
      "  'summary': 'Create Journey Application Note',\n",
      "  'tag': 'Journeys'},\n",
      " {'description': 'If a journey application has the status '\n",
      "                 '`pending_journey_application_review`, this endpoint can be '\n",
      "                 'used to inform the system of the outcome of the manual '\n",
      "                 'review and submit review notes. The outcome submitted here '\n",
      "                 'will be the final outcome of the journey application.',\n",
      "  'method': 'post',\n",
      "  'path': '/journeys/{journey_token}/applications/{journey_application_token}/review',\n",
      "  'summary': 'Manual Review Journey Application',\n",
      "  'tag': 'Journeys'},\n",
      " {'description': 'Retrieve all notes associated with the specified Journey '\n",
      "                 'Application',\n",
      "  'method': 'get',\n",
      "  'path': '/journeys/{journey_token}/applications/{journey_application_token}/notes',\n",
      "  'summary': 'Get Journey Application Notes',\n",
      "  'tag': 'Journeys'}]\n"
     ]
    }
   ],
   "source": [
    "relevant_docs = retriever.invoke(query)\n",
    "pprint(list(map(lambda doc: doc.metadata, relevant_docs)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "fbfe01c5-274b-4cff-a37c-db57642bcadd",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "better_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"You are a world-class solutions engineer and amazing at question-answering tasks. If you don't know the answer, just say that you don't know. Use markdown to ensure code blocks and commands are propertly formatted. Make sure to always include environment setup instructions and code blocks that are helpful for a developer to copy-paste. Always explain inputs and outputs of API requests. Be as detailed as possible. Answer the user's questions based on the below context:\\n\\n{context}\",\n",
    "        ),\n",
    "        (\n",
    "            \"user\",\n",
    "            \"{question}\"\n",
    "        )\n",
    "    ]\n",
    ")\n",
    "\n",
    "def format_docs(docs):\n",
    "    return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
    "\n",
    "rag_chain = (\n",
    "    {\"context\": retriever | format_docs, \"question\": RunnablePassthrough()}\n",
    "    | better_prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "dcfa6e84-1850-4bb9-bb2d-54c5e90a68f2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey application using the Alloy API in Python, you will need to send a POST request to the `/journeys/{journey_token}/applications` endpoint with the required payload. Here's a step-by-step guide on how to achieve this:\n",
       "\n",
       "### Step 1: Install the Requests library\n",
       "You can use the Requests library to make HTTP requests in Python. If you don't have it installed, you can install it using pip:\n",
       "\n",
       "```bash\n",
       "pip install requests\n",
       "```\n",
       "\n",
       "### Step 2: Make a POST request to create a journey application\n",
       "Here's a sample Python script that demonstrates how to create a journey application using the Alloy API:\n",
       "\n",
       "```python\n",
       "import requests\n",
       "import json\n",
       "\n",
       "# Define the endpoint URL and journey token\n",
       "url = \"https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications\"\n",
       "journey_token = \"your_journey_token_here\"\n",
       "\n",
       "# Define the payload for creating a journey application\n",
       "payload = {\n",
       "    \"do_await_additional_entities\": False,\n",
       "    \"entities\": [\n",
       "        {\n",
       "            \"branch_name\": \"persons\",\n",
       "            \"data\": {\n",
       "                \"addresses\": [\n",
       "                    {\n",
       "                        \"city\": \"New York\",\n",
       "                        \"country_code\": \"US\",\n",
       "                        \"line_1\": \"41 E. 11th\",\n",
       "                        \"line_2\": \"2nd floor\",\n",
       "                        \"postal_code\": \"10003\",\n",
       "                        \"state\": \"NY\",\n",
       "                        \"type\": \"primary\"\n",
       "                    }\n",
       "                ],\n",
       "                \"birth_date\": \"1990-01-25\",\n",
       "                \"document_ssn\": \"111223333\",\n",
       "                \"email_address\": \"john@alloy.com\",\n",
       "                \"ip_address_v4\": \"42.206.213.70\",\n",
       "                \"meta\": {\n",
       "                    \"user_type\": \"vip\"\n",
       "                },\n",
       "                \"name_first\": \"John\",\n",
       "                \"name_last\": \"Doe\",\n",
       "                \"name_middle\": \"Franklin\",\n",
       "                \"phone_number\": \"8443825569\"\n",
       "            },\n",
       "            \"entity_type\": \"person\",\n",
       "            \"external_entity_id\": \"my_system_entity_id_123\"\n",
       "        }\n",
       "    ]\n",
       "}\n",
       "\n",
       "# Convert the payload to JSON\n",
       "payload_json = json.dumps(payload)\n",
       "\n",
       "# Make the POST request\n",
       "response = requests.post(url.format(journey_token=journey_token), json=payload_json)\n",
       "\n",
       "# Print the response\n",
       "print(response.status_code)\n",
       "print(response.json())\n",
       "```\n",
       "\n",
       "### Step 3: Replace placeholders\n",
       "- Replace `your_journey_token_here` with the actual journey token you want to use.\n",
       "- Update the payload with the necessary data for your journey application.\n",
       "\n",
       "### Step 4: Run the script\n",
       "Save the script to a Python file (e.g., `create_journey_application.py`) and run it. This will create a journey application using the Alloy API.\n",
       "\n",
       "Make sure to handle any authentication requirements (OAuth2 or Basic Auth) as per the Alloy API documentation.\n",
       "\n",
       "This script will send a POST request to create a journey application with the specified data. The response will contain the details of the created journey application.\n",
       "\n",
       "If you have any specific authentication requirements or need further assistance, please let me know!"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "output = rag_chain.invoke(query)\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b58fee8f-43b9-4086-b130-3cba5ff5f311",
   "metadata": {},
   "source": [
    "### 👎 Looks like we are missing security requirements\n",
    "\n",
    "Notice how the naive approach includes directions on how to authenticate with the endpoint as well. One thing that the naive approach doesn't include is both authentication options: basic & OAuth.\n",
    "\n",
    "### 🤔 Lets make sure the model has all the necessary information to infer security requirements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "2aee72f4-f7a3-4565-9b7d-a5a69a66220b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_id: 626c513d1c9b07002812708b\n",
      "info:\n",
      "  description: hey hey hey, it's the Alloy API!\n",
      "  title: Alloy API\n",
      "  version: 1.0.0\n",
      "openapi: 3.0.0\n",
      "paths:\n",
      "  /journeys/{journey_token}/applications:\n",
      "    post:\n",
      "      description: 'Create a journey application for one or more entities.\n",
      "\n",
      "        '\n",
      "      requestBody:\n",
      "        content:\n",
      "          application/json:\n",
      "            schema:\n",
      "              properties:\n",
      "                do_await_additional_entities:\n",
      "                  default: false\n",
      "                  description: 'If this value is true, additional entities can be\n",
      "                    sent after this request by using the PUT endpoint that updates\n",
      "                    a journey application.\n",
      "\n",
      "\n",
      "                    The journey application will not complete until the parameter\n",
      "                    `has_finished_sending_additional_entities` is sent with the value\n",
      "                    `true` to the PUT endpoint.\n",
      "\n",
      "                    '\n",
      "                  example: false\n",
      "                  type: boolean\n",
      "                entities:\n",
      "                  description: 'List of entities to be processed in this Application.\n",
      "\n",
      "                    '\n",
      "                  example:\n",
      "                  - branch_name: persons\n",
      "                    data:\n",
      "                      addresses:\n",
      "                      - city: New York\n",
      "                        country_code: US\n",
      "                        line_1: 41 E. 11th\n",
      "                        line_2: 2nd floor\n",
      "                        postal_code: 10003\n",
      "                        state: NY\n",
      "                        type: primary\n",
      "                      birth_date: '1990-01-25'\n",
      "                      document_ssn: 111223333\n",
      "                      email_address: john@alloy.com\n",
      "                      ip_address_v4: 42.206.213.70\n",
      "                      meta:\n",
      "                        user_type: vip\n",
      "                      name_first: John\n",
      "                      name_last: Doe\n",
      "                      name_middle: Franklin\n",
      "                      phone_number: 8443825569\n",
      "                    entity_type: person\n",
      "                    external_entity_id: my_system_entity_id_123\n",
      "                  - branch_name: businesses\n",
      "                    data:\n",
      "                      addresses:\n",
      "                      - city: New York\n",
      "                        country_code: US\n",
      "                        line_1: 41 E. 11th\n",
      "                        line_2: 2nd floor\n",
      "                        postal_code: 10003\n",
      "                        state: NY\n",
      "                        type: business_primary\n",
      "                      business_federal_ein: 122334455\n",
      "                      business_name: Acme Corporation\n",
      "                      business_phone_number: 111222333\n",
      "                      business_website: https://www.acmeco.com/\n",
      "                      meta:\n",
      "                        sic_code: 1531\n",
      "                      representatives:\n",
      "                      - addresses:\n",
      "                        - city: New York\n",
      "                          country_code: US\n",
      "                          line_1: 41 E. 11th\n",
      "                          line_2: 2nd floor\n",
      "                          postal_code: 10003\n",
      "                          state: NY\n",
      "                          type: primary\n",
      "                        birth_date: '1990-01-25'\n",
      "                        document_ssn: 111223333\n",
      "                        email_address: john@alloy.com\n",
      "                        name_first: John\n",
      "                        name_last: Doe\n",
      "                        name_middle: Franklin\n",
      "                        phone_number: 8443825569\n",
      "                        type: principal_owner\n",
      "                    entity_type: business\n",
      "                    external_entity_id: my_system_entity_id_345\n",
      "                  items:\n",
      "                    anyOf:\n",
      "                    - allOf:\n",
      "                      - properties:\n",
      "                          data:\n",
      "                            description: 'Contains the fields for each input attribute\n",
      "                              of each workflow in the journey that is expected to\n",
      "                              be processed for the entity.\n",
      "\n",
      "                              '\n",
      "                            properties:\n",
      "                              addresses:\n",
      "                                description: 'List of addresses for the given entity.\n",
      "\n",
      "                                  '\n",
      "                                items:\n",
      "                                  description: Full address for a person entity\n",
      "                                  properties: &id001\n",
      "                                    city:\n",
      "                                      example: New York\n",
      "                                      type: string\n",
      "                                    country_code:\n",
      "                                      example: US\n",
      "                                      type: string\n",
      "                                    line_1:\n",
      "                                      example: 41 E. 11th\n",
      "                                      type: string\n",
      "                                    line_2:\n",
      "                                      example: 2nd floor\n",
      "                                      type: string\n",
      "                                    postal_code:\n",
      "                                      example: 10003\n",
      "                                      type: string\n",
      "                                    state:\n",
      "                                      example: NY\n",
      "                                      type: string\n",
      "                                    type:\n",
      "                                      description: Allowed values are `\"primary\"`,\n",
      "                                        `\"secondary\"`, `\"previous\"`, `\"mailing\"`,\n",
      "                                        `\"shipping\"`, `\"service\"`, `\"other\"`\n",
      "                                      example: primary\n",
      "                                      type: string\n",
      "                                  type: object\n",
      "                                type: array\n",
      "                              birth_date:\n",
      "                                example: '1990-01-25'\n",
      "                                type: string\n",
      "                              document_id_card:\n",
      "                                description: ID card number\n",
      "                                example: 1122334455\n",
      "                                type: string\n",
      "                              document_license:\n",
      "                                description: U.S. issued driver's license number\n",
      "                                example: 111222333\n",
      "                                type: string\n",
      "                              document_national_id:\n",
      "                                description: National ID number for a non-US person\n",
      "                                  entity.\n",
      "                                example: 111223333\n",
      "                                type: string\n",
      "                              document_passport:\n",
      "                                description: Passport number\n",
      "                                example: 123456789\n",
      "                                type: string\n",
      "                              document_ssn:\n",
      "                                description: Social Security number.\n",
      "                                example: 111223333\n",
      "                                type: string\n",
      "                              email_address:\n",
      "                                example: john@alloy.com\n",
      "                                type: string\n",
      "                              gender:\n",
      "                                example: male\n",
      "                                type: string\n",
      "                              ip_address_v4:\n",
      "                                example: 42.206.213.70\n",
      "                                type: string\n",
      "                              meta:\n",
      "                                description: Any additional metadata to be accessed\n",
      "                                  for decisioning or review purposes that are not\n",
      "                                  sent to a data service can be referenced here.\n",
      "                                example:\n",
      "                                  user_type: vip\n",
      "                                type: object\n",
      "                              name_first:\n",
      "                                example: John\n",
      "                                type: string\n",
      "                              name_last:\n",
      "                                example: Doe\n",
      "                                type: string\n",
      "                              name_middle:\n",
      "                                example: Franklin\n",
      "                                type: string\n",
      "                              phone_number:\n",
      "                                example: 8443825569\n",
      "                                type: string\n",
      "                            type: object\n",
      "                          external_entity_id:\n",
      "                            description: 'The value used on client''s own system to\n",
      "                              identify the entity.\n",
      "\n",
      "\n",
      "                              If an entity associated with the value passed in already\n",
      "                              exists, then the entity application processes for that\n",
      "                              entity. Otherwise, a new entity is created and associated\n",
      "                              with the value passed in.\n",
      "\n",
      "\n",
      "                              This parameter is optional, but strongly encouraged.\n",
      "\n",
      "                              '\n",
      "                            example: my_system_entity_id_123\n",
      "                            type: string\n",
      "                        required:\n",
      "                        - data\n",
      "                        type: object\n",
      "                      - properties:\n",
      "                          branch_name:\n",
      "                            default: persons\n",
      "                            description: 'This value is required for journeys with\n",
      "                              multiple branches. It must match a journey branch configured\n",
      "                              from the start node. It is used to determine\n",
      "\n",
      "                              which steps the entity will be required to complete.\n",
      "\n",
      "                              '\n",
      "                            example: my_person_branch_name\n",
      "                            type: string\n",
      "                          entity_token:\n",
      "                            description: 'The token associated with an existing entity.\n",
      "\n",
      "\n",
      "                              By passing a value for this field, the entity application\n",
      "                              processes for the existing entity associated with the\n",
      "                              token.\n",
      "\n",
      "                              '\n",
      "                            example: P-1GoQALm40nPQSp7UVTJS\n",
      "                            type: string\n",
      "                          entity_type:\n",
      "                            default: person\n",
      "                            description: If left blank, defaults to `\"person\"`.\n",
      "                            enum:\n",
      "                            - person\n",
      "                            - business\n",
      "                            example: person\n",
      "                            type: string\n",
      "                        type: object\n",
      "                    - allOf:\n",
      "                      - properties:\n",
      "                          data:\n",
      "                            description: 'Contains the fields for each input attribute\n",
      "                              of each workflow in the journey that is expected to\n",
      "                              be processed for the entity.\n",
      "\n",
      "                              '\n",
      "                            properties:\n",
      "                              addresses:\n",
      "                                description: 'List of addresses for the given entity.\n",
      "\n",
      "                                  '\n",
      "                                items:\n",
      "                                  description: Full address for a business entity\n",
      "                                  properties:\n",
      "                                    city:\n",
      "                                      example: New York\n",
      "                                      type: string\n",
      "                                    country_code:\n",
      "                                      example: US\n",
      "                                      type: string\n",
      "                                    line_1:\n",
      "                                      example: 41 E. 11th\n",
      "                                      type: string\n",
      "                                    line_2:\n",
      "                                      example: 2nd floor\n",
      "                                      type: string\n",
      "                                    postal_code:\n",
      "                                      example: 10003\n",
      "                                      type: string\n",
      "                                    state:\n",
      "                                      example: NY\n",
      "                                      type: string\n",
      "                                    type:\n",
      "                                      description: Allowed values are `\"business_primary\"`,\n",
      "                                        `\"business_secondary\"`, `\"business_previous\"`\n",
      "                                      example: business_primary\n",
      "                                      type: string\n",
      "                                  type: object\n",
      "                                type: array\n",
      "                              business_federal_ein:\n",
      "                                description: Business federal employer ID number for\n",
      "                                  US business entities.\n",
      "                                example: 122334455\n",
      "                                type: string\n",
      "                              business_name:\n",
      "                                example: Acme Corporation\n",
      "                                type: string\n",
      "                              business_phone_number:\n",
      "                                description: Business phone number.\n",
      "                                example: 111222333\n",
      "                                type: string\n",
      "                              business_registry_id:\n",
      "                                description: Business registry ID number for non-US\n",
      "                                  business entities.\n",
      "                                example: 122334455\n",
      "                                type: string\n",
      "                              business_website:\n",
      "                                description: Business website.\n",
      "                                example: https://www.acmeco.com/\n",
      "                                type: string\n",
      "                              meta:\n",
      "                                description: Any additional metadata to be accessed\n",
      "                                  for decisioning or review purposes that are not\n",
      "                                  sent to a data service can be referenced here.\n",
      "                                example:\n",
      "                                  sic_code: 1531\n",
      "                                type: object\n",
      "                              representatives:\n",
      "                                description: List of ultimate beneficial owners associated\n",
      "                                  to the business.\n",
      "                                items:\n",
      "                                  description: Ultimate beneficial owners associated\n",
      "                                    to the business.\n",
      "                                  properties:\n",
      "                                    addresses:\n",
      "                                      description: 'List of addresses for the given\n",
      "                                        entity.\n",
      "\n",
      "                                        '\n",
      "                                      items:\n",
      "                                        description: Full address for a person entity\n",
      "                                        properties: *id001\n",
      "                                        type: object\n",
      "                                      type: array\n",
      "                                    birth_date:\n",
      "                                      example: '1990-01-25'\n",
      "                                      type: string\n",
      "                                    document_ssn:\n",
      "                                      description: Social Security number\n",
      "                                      example: 111223333\n",
      "                                      type: string\n",
      "                                    email_address:\n",
      "                                      example: john@alloy.com\n",
      "                                      type: string\n",
      "                                    name_first:\n",
      "                                      example: John\n",
      "                                      type: string\n",
      "                                    name_last:\n",
      "                                      example: Doe\n",
      "                                      type: string\n",
      "                                    name_middle:\n",
      "                                      example: Franklin\n",
      "                                      type: string\n",
      "                                    phone_number:\n",
      "                                      example: 8443825569\n",
      "                                      type: string\n",
      "                                    type:\n",
      "                                      description: Allowed values are `\"principal_owner\"`\n",
      "                                        or `\"authorized_signer\"`.\n",
      "                                      example: principal_owner\n",
      "                                      type: string\n",
      "                                  type: object\n",
      "                                type: array\n",
      "                            type: object\n",
      "                          external_entity_id:\n",
      "                            description: 'The value used on client''s own system to\n",
      "                              identify the entity.\n",
      "\n",
      "                              If an entity associated with the value passed in already\n",
      "                              exists, then the entity application processes for that\n",
      "                              entity. Otherwise, a new entity is created and associated\n",
      "                              with the value passed in.\n",
      "\n",
      "                              This parameter is optional, but strongly encouraged.\n",
      "\n",
      "                              '\n",
      "                            example: my_system_entity_id_345\n",
      "                            type: string\n",
      "                        required:\n",
      "                        - data\n",
      "                        type: object\n",
      "                      - properties:\n",
      "                          branch_name:\n",
      "                            default: businesses\n",
      "                            description: 'This value is required for journeys with\n",
      "                              multiple branches. It must match a journey branch configured\n",
      "                              from the start node. It is used to determine\n",
      "\n",
      "                              which steps the entity will be required to complete.\n",
      "\n",
      "                              '\n",
      "                            example: my_business_branch_name\n",
      "                            type: string\n",
      "                          entity_token:\n",
      "                            description: 'The token associated with an existing entity.\n",
      "\n",
      "                              By passing a value for this field, the entity application\n",
      "                              processes for the existing entity associated with the\n",
      "                              token.\n",
      "\n",
      "                              '\n",
      "                            example: B-4vaKI3CAgBvpdLpMifon\n",
      "                            type: string\n",
      "                          entity_type:\n",
      "                            default: business\n",
      "                            description: If left blank, defaults to `\"person\"`.\n",
      "                            example: business\n",
      "                            type: string\n",
      "                        type: object\n",
      "                      title: Business Entity\n",
      "                  type: array\n",
      "                external_group_id:\n",
      "                  description: 'Optional, but if you have an identifier in your system\n",
      "                    that represents the entire Application\n",
      "\n",
      "                    (meaning, all the person or persons applying for this product),\n",
      "                    include it here. This identifier must be unique.\n",
      "\n",
      "                    '\n",
      "                  example: my_system_group_id_456\n",
      "                  type: string\n",
      "                external_product_id:\n",
      "                  description: 'Optional, but if you have an identifier in your system\n",
      "                    for the product that this\n",
      "\n",
      "                    application is applying for, include it here.\n",
      "\n",
      "                    '\n",
      "                  example: my_system_product_id_789\n",
      "                  type: string\n",
      "              required:\n",
      "              - entities\n",
      "      responses:\n",
      "        '201':\n",
      "          content:\n",
      "            application/json:\n",
      "              schema:\n",
      "                oneOf:\n",
      "                - allOf:\n",
      "                  - title: When header `alloy-journey-override-sync` is set to `true`\n",
      "                  - properties:\n",
      "                      _links:\n",
      "                        properties:\n",
      "                          self:\n",
      "                            properties:\n",
      "                              href:\n",
      "                                description: GET route for the Application\n",
      "                                example: /v1/journeys/J-Kq8jlFcA4veeHCtt823h/applications/JA-LS0GHKjDNhY6dGlvYxxH\n",
      "                                type: string\n",
      "                            type: object\n",
      "                        type: object\n",
      "                      journey_application_token:\n",
      "                        example: JA-LS0GHKjDNhY6dGlvYxxH\n",
      "                        type: string\n",
      "                    type: object\n",
      "                - allOf:\n",
      "                  - title: When header `alloy-journey-override-sync` is set to `false`\n",
      "                      or not passed in\n",
      "                  - example:\n",
      "                      _embedded:\n",
      "                        child_entities:\n",
      "                        - created: '2021-10-12T20:38:26.493Z'\n",
      "                          entity_application_outcome: approved\n",
      "                          entity_application_status: completed\n",
      "                          entity_application_token: EA-GessHRonFRTSXCmErk7J\n",
      "                          external_entity_identifier: external_entity_id123\n",
      "                          name: John Doe\n",
      "                          token: P-tZOLIOQGVxfixICuvkS0\n",
      "                          type: person\n",
      "                        entity:\n",
      "                          external_entity_identifier: null\n",
      "                          name: null\n",
      "                          token: G-wBdsvC7hA84j7p4PTVcD\n",
      "                          type: group\n",
      "                        entity_applications:\n",
      "                        - entity_application_outcome: approved\n",
      "                          entity_application_status: completed\n",
      "                          entity_application_status_details: null\n",
      "                          entity_application_token: EA-GessHRonFRTSXCmErk7J\n",
      "                          entity_token: P-tZOLIOQGVxfixICuvkS0\n",
      "                          output:\n",
      "                            matrix_models:\n",
      "                              my_matrix:\n",
      "                                matrix_model_public_version: 5\n",
      "                                matrix_model_token: MM-Z37VkZwHMbnzhLJM7ZlX\n",
      "                                name: my_matrix\n",
      "                                result: 15\n",
      "                                status: executed\n",
      "                                x_bucket: 1\n",
      "                                x_value: 1000\n",
      "                                y_bucket: 0\n",
      "                                y_value: 300\n",
      "                            outcome_reasons:\n",
      "                            - name: Fraud Risk\n",
      "                              type: null\n",
      "                            output_attributes:\n",
      "                              income_calculation: 98000\n",
      "                            tags:\n",
      "                            - fraud_tag\n",
      "                            - Fraud Risk\n",
      "                        events:\n",
      "                        - _embedded:\n",
      "                            node:\n",
      "                              config:\n",
      "                                workflow_token: vUr2Fs1y8Qiz1a79kNJk1dk7EfYUAJRK\n",
      "                                workflow_version_id: 1\n",
      "                              id: '1632850505316'\n",
      "                              name: null\n",
      "                              type: workflow\n",
      "                          _links: {}\n",
      "                          entity_token: null\n",
      "                          timestamp: 1634059958414\n",
      "                          type: started_application\n",
      "                        - _embedded:\n",
      "                            node:\n",
      "                              config:\n",
      "                                workflow_token: vUr2Fs1y8Qiz1a79kNJk1dk7EfYUAJRK\n",
      "                                workflow_version_id: 1\n",
      "                              id: '1632850505316'\n",
      "                              name: null\n",
      "                              type: workflow\n",
      "                          _links:\n",
      "                            evaluation:\n",
      "                              href: /v1/evaluations/L-Vn9uOp0ZyYvjDL1t3Sd7\n",
      "                          entity_token: null\n",
      "                          evaluation_token: L-Vn9uOp0ZyYvjDL1t3Sd7\n",
      "                          sdk_config:\n",
      "                            documents:\n",
      "                            - passport\n",
      "                            selfie: true\n",
      "                          timestamp: 1634059958531\n",
      "                          type: started_evaluation\n",
      "                        - _embedded:\n",
      "                            node:\n",
      "                              config:\n",
      "                                workflow_token: vUr2Fs1y8Qiz1a79kNJk1dk7EfYUAJRK\n",
      "                                workflow_version_id: 1\n",
      "                              id: '1632850505316'\n",
      "                              name: null\n",
      "                              type: workflow\n",
      "                          _links:\n",
      "                            evaluation:\n",
      "                              href: /v1/evaluations/L-Vn9uOp0ZyYvjDL1t3Sd7\n",
      "                          entity_token: P-tZOLIOQGVxfixICuvkS0\n",
      "                          evaluation_token: L-Vn9uOp0ZyYvjDL1t3Sd7\n",
      "                          outcome: Approved\n",
      "                          timestamp: 1634059960557\n",
      "                          type: completed_evaluation\n",
      "                        - _embedded:\n",
      "                            node:\n",
      "                              config:\n",
      "                                outcome: Approved\n",
      "                              id: '1633639581306'\n",
      "                              name: null\n",
      "                              type: outcome\n",
      "                          _links: {}\n",
      "                          entity_token: P-tZOLIOQGVxfixICuvkS0\n",
      "                          outcome: Approved\n",
      "                          timestamp: 1634059961453\n",
      "                          type: completed_application\n",
      "                        journey:\n",
      "                          _links:\n",
      "                            callback_by_entity_application_token:\n",
      "                              href: /v1/journeys/J-rTE9lsgkluEMB6pWp6Y5/applications/JA-iLh1wxtrpfGuncHQVcwK/nodes/97b927fe-637b-42be-aa70-1e998ad57bb3\n",
      "                            self:\n",
      "                              href: /v1/journeys/J-qDydegaMK8otdsRYquOR\n",
      "                          journey_name: ''\n",
      "                          journey_token: J-qDydegaMK8otdsRYquOR\n",
      "                          journey_type: application\n",
      "                        rerun:\n",
      "                          initiated_by: dashboard\n",
      "                          previous_journey_application_token: JA-zvtpApEGBnmKepPwygBx\n",
      "                          root_external_group_id: null\n",
      "                          root_journey_application_token: JA-zvtpApEGBnmKepPwygBx\n",
      "                      _links:\n",
      "                        self:\n",
      "                          href: /v1/journeys/J-qDydegaMK8otdsRYquOR/applications/JA-ddjP31DhduTI334Cs3uT\n",
      "                      annual_interest_rate: '70'\n",
      "                      closed_at: 1634059961464\n",
      "                      complete_outcome: Approved\n",
      "                      created_at: 1634059958368\n",
      "                      credit_limit: '42'\n",
      "                      is_rerun: true\n",
      "                      journey_application_token: JA-ddjP31DhduTI334Cs3uT\n",
      "                      recent_outcome: Approved\n",
      "                      sandbox: false\n",
      "                      status: completed\n",
      "                      terminal_reconciliation_output:\n",
      "                        matrix_models:\n",
      "                          my_matrix:\n",
      "                            matrix_model_public_version: 5\n",
      "                            matrix_model_token: MM-Z37VkZwHMbnzhLJM7ZlX\n",
      "                            name: my_matrix\n",
      "                            result: 15\n",
      "                            status: executed\n",
      "                            x_bucket: 1\n",
      "                            x_value: 1000\n",
      "                            y_bucket: 0\n",
      "                            y_value: 300\n",
      "                        outcome_reasons:\n",
      "                        - name: Fraud Risk\n",
      "                          type: null\n",
      "                        output_attributes:\n",
      "                          income_calculation: 98000\n",
      "                        tags:\n",
      "                        - fraud_tag\n",
      "                        - Fraud Risk\n",
      "                      updated_at: 1634059961458\n",
      "                    properties:\n",
      "                      _embedded:\n",
      "                        properties:\n",
      "                          child_entities:\n",
      "                            items:\n",
      "                              properties:\n",
      "                                created:\n",
      "                                  type: string\n",
      "                                entity_application_branch_name:\n",
      "                                  type: string\n",
      "                                entity_application_outcome:\n",
      "                                  type: string\n",
      "                                entity_application_status:\n",
      "                                  type: string\n",
      "                                entity_application_token:\n",
      "                                  type: string\n",
      "                                external_entity_identifier:\n",
      "                                  type: string\n",
      "                                name:\n",
      "                                  type: string\n",
      "                                sandbox_persona_name:\n",
      "                                  description: When applicable, name of sandbox persona\n",
      "                                    used for this child entity\n",
      "                                  type: string\n",
      "                                token:\n",
      "                                  type: string\n",
      "                                type:\n",
      "                                  type: string\n",
      "                              type: object\n",
      "                            type: array\n",
      "                          entity:\n",
      "                            description: The journey application entity\n",
      "                            properties:\n",
      "                              external_entity_identifier:\n",
      "                                type: string\n",
      "                              name:\n",
      "                                type: string\n",
      "                              token:\n",
      "                                type: string\n",
      "                              type:\n",
      "                                type: string\n",
      "                            type: object\n",
      "                          entity_applications:\n",
      "                            items:\n",
      "                              properties:\n",
      "                                entity_application_outcome:\n",
      "                                  type: string\n",
      "                                entity_application_status:\n",
      "                                  type: string\n",
      "                                entity_application_status_details:\n",
      "                                  description: Additional details for applications\n",
      "                                    that have status `data_request`\n",
      "                                  properties:\n",
      "                                    optional:\n",
      "                                      items:\n",
      "                                        properties:\n",
      "                                          description:\n",
      "                                            type: string\n",
      "                                          key:\n",
      "                                            type: string\n",
      "                                          regex:\n",
      "                                            type: string\n",
      "                                          type:\n",
      "                                            type: string\n",
      "                                        type: object\n",
      "                                      type: array\n",
      "                                    or:\n",
      "                                      type: string\n",
      "                                    required:\n",
      "                                      items:\n",
      "                                        properties:\n",
      "                                          description:\n",
      "                                            type: string\n",
      "                                          key:\n",
      "                                            type: string\n",
      "                                          message:\n",
      "                                            type: string\n",
      "                                          regex:\n",
      "                                            type: string\n",
      "                                          type:\n",
      "                                            type: string\n",
      "                                        type: object\n",
      "                                      type: array\n",
      "                                  type: object\n",
      "                                entity_application_token:\n",
      "                                  type: string\n",
      "                                entity_token:\n",
      "                                  type: string\n",
      "                                output:\n",
      "                                  allOf:\n",
      "                                  - properties: &id002\n",
      "                                      matrix_models:\n",
      "                                        additionalProperties:\n",
      "                                          description: NOTE the dynamic property name\n",
      "                                            refers to the name of the matrix model\n",
      "                                          properties:\n",
      "                                            matrix_model_public_version:\n",
      "                                              type: integer\n",
      "                                            matrix_model_token:\n",
      "                                              type: string\n",
      "                                            name:\n",
      "                                              type: string\n",
      "                                            result:\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                            status:\n",
      "                                              enum:\n",
      "                                              - executed\n",
      "                                              - not_executed\n",
      "                                              type: string\n",
      "                                            x_bucket:\n",
      "                                              description: x-coordinate of the matrix\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                            x_value:\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                            y_bucket:\n",
      "                                              description: y-coordinate of the matrix\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                            y_value:\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                          type: object\n",
      "                                        type: object\n",
      "                                      outcome_reasons:\n",
      "                                        items:\n",
      "                                          properties:\n",
      "                                            name:\n",
      "                                              type: string\n",
      "                                            type:\n",
      "                                              enum:\n",
      "                                              - adverse_action\n",
      "                                              - null\n",
      "                                              type: string\n",
      "                                          type: object\n",
      "                                        type: array\n",
      "                                      output_attributes:\n",
      "                                        additionalProperties:\n",
      "                                          description: NOTE the dynamic property name\n",
      "                                            refers to the name of the output attribute\n",
      "                                          oneOf:\n",
      "                                          - type: string\n",
      "                                          - type: number\n",
      "                                        type: object\n",
      "                                      tags:\n",
      "                                        items:\n",
      "                                          type: string\n",
      "                                        type: array\n",
      "                                    type: object\n",
      "                                  description: Data aggregated from the outputs of\n",
      "                                    every evaluation run for the entity application\n",
      "                                  type: object\n",
      "                              type: object\n",
      "                            type: array\n",
      "                          events:\n",
      "                            description: List of journey application events, ordered\n",
      "                              chronologically. The fields displayed in the event will\n",
      "                              depend on the event type\n",
      "                            items:\n",
      "                              properties:\n",
      "                                _embedded:\n",
      "                                  properties:\n",
      "                                    node:\n",
      "                                      properties:\n",
      "                                        config:\n",
      "                                          description: Config related to the specific\n",
      "                                            node, depending on the type\n",
      "                                          type: object\n",
      "                                        id:\n",
      "                                          type: string\n",
      "                                        name:\n",
      "                                          type: string\n",
      "                                        sdk_config:\n",
      "                                          description: Settings to be read by SDK\n",
      "                                            to handle processing. Only present on\n",
      "                                            workflow node events.\n",
      "                                          properties:\n",
      "                                            documents:\n",
      "                                              items:\n",
      "                                                type: string\n",
      "                                              type: array\n",
      "                                            selfie:\n",
      "                                              type: boolean\n",
      "                                          type: object\n",
      "                                        type:\n",
      "                                          enum:\n",
      "                                          - start\n",
      "                                          - workflow\n",
      "                                          - review\n",
      "                                          - outcome\n",
      "                                          - action\n",
      "                                          - docv\n",
      "                                          type: string\n",
      "                                        workflow_name:\n",
      "                                          type: string\n",
      "                                      type: object\n",
      "                                  type: object\n",
      "                                _links:\n",
      "                                  properties:\n",
      "                                    case:\n",
      "                                      properties:\n",
      "                                        href:\n",
      "                                          type: string\n",
      "                                      type: object\n",
      "                                    evaluation:\n",
      "                                      properties:\n",
      "                                        href:\n",
      "                                          type: string\n",
      "                                      type: object\n",
      "                                  type: object\n",
      "                                entity_application_token:\n",
      "                                  type: string\n",
      "                                entity_token:\n",
      "                                  type: string\n",
      "                                error_data:\n",
      "                                  description: Additional error data populated when\n",
      "                                    available for `error` event types\n",
      "                                  properties:\n",
      "                                    application_token:\n",
      "                                      type: string\n",
      "                                    application_version_id:\n",
      "                                      type: integer\n",
      "                                    entity_token:\n",
      "                                      type: string\n",
      "                                    error:\n",
      "                                      properties:\n",
      "                                        details:\n",
      "                                          type: object\n",
      "                                        error_token:\n",
      "                                          type: string\n",
      "                                        message:\n",
      "                                          type: string\n",
      "                                        minor_code:\n",
      "                                          type: integer\n",
      "                                        type:\n",
      "                                          type: string\n",
      "                                      type: object\n",
      "                                    evaluation_token:\n",
      "                                      type: string\n",
      "                                    status_code:\n",
      "                                      type: integer\n",
      "                                    timestamp:\n",
      "                                      type: integer\n",
      "                                  type: object\n",
      "                                evaluation_token:\n",
      "                                  description: Identifying evaluation token (only\n",
      "                                    in evaluation type events)\n",
      "                                  type: string\n",
      "                                external_group_id:\n",
      "                                  type: string\n",
      "                                external_partner_id:\n",
      "                                  type: string\n",
      "                                journey_application_event_token:\n",
      "                                  type: string\n",
      "                                journey_application_token:\n",
      "                                  type: string\n",
      "                                journey_type:\n",
      "                                  enum:\n",
      "                                  - alert\n",
      "                                  - application\n",
      "                                  type: string\n",
      "                                outcome:\n",
      "                                  description: 'Populated for the following event\n",
      "                                    types: `completed_action`, `completed_application`,\n",
      "                                    `completed_branch`, `completed_evaluation`, `completed_review`,\n",
      "                                    `pending_action_expired`'\n",
      "                                  type: string\n",
      "                                reason:\n",
      "                                  type: string\n",
      "                                reasons:\n",
      "                                  items:\n",
      "                                    type: string\n",
      "                                  type: array\n",
      "                                timestamp:\n",
      "                                  type: integer\n",
      "                                type:\n",
      "                                  enum:\n",
      "                                  - application_expired\n",
      "                                  - completed_action\n",
      "                                  - completed_application\n",
      "                                  - completed_branch\n",
      "                                  - completed_evaluation\n",
      "                                  - completed_reconciliation\n",
      "                                  - completed_review\n",
      "                                  - completed_review_journey_application\n",
      "                                  - data_request_evaluation\n",
      "                                  - error\n",
      "                                  - has_finished_sending_additional_entities\n",
      "                                  - pending_action\n",
      "                                  - pending_action_expired\n",
      "                                  - pending_documents\n",
      "                                  - pending_review\n",
      "                                  - pending_step_up\n",
      "                                  - pending_workflow_service\n",
      "                                  - reached_auto_decision_node\n",
      "                                  - started_application\n",
      "                                  - started_evaluation\n",
      "                                  - started_reconciliation\n",
      "                                  type: string\n",
      "                              type: object\n",
      "                            type: array\n",
      "                          journey:\n",
      "                            properties:\n",
      "                              _links:\n",
      "                                properties:\n",
      "                                  callback_by_entity_application_token:\n",
      "                                    description: When applicable, the route to send\n",
      "                                      a PUT request to for each entity application\n",
      "                                      to resolve its current pending state\n",
      "                                    type: object\n",
      "                                  self:\n",
      "                                    properties:\n",
      "                                      href:\n",
      "                                        description: GET route for the Journey\n",
      "                                        type: string\n",
      "                                    type: object\n",
      "                                type: object\n",
      "                              journey_name:\n",
      "                                type: string\n",
      "                              journey_token:\n",
      "                                type: string\n",
      "                              journey_type:\n",
      "                                enum:\n",
      "                                - application\n",
      "                                - alert\n",
      "                                type: string\n",
      "                              journey_version_num:\n",
      "                                type: string\n",
      "                            type: object\n",
      "                          multi_environment_config:\n",
      "                            allOf:\n",
      "                            - properties:\n",
      "                                actions:\n",
      "                                  description: List of journey actions that have been\n",
      "                                    configured as part of this Multi-Environment Configuration.\n",
      "                                  items:\n",
      "                                    properties:\n",
      "                                      action_name:\n",
      "                                        type: string\n",
      "                                      action_version:\n",
      "                                        type: number\n",
      "                                      journey_action_id:\n",
      "                                        type: number\n",
      "                                      outcome:\n",
      "                                        description: The outcome that all action nodes\n",
      "                                          for this journey action will be decisioned\n",
      "                                          to.\n",
      "                                        type: string\n",
      "                                    type: object\n",
      "                                  type: array\n",
      "                                created_at:\n",
      "                                  type: string\n",
      "                                journey_name:\n",
      "                                  type: string\n",
      "                                journey_public_version:\n",
      "                                  type: number\n",
      "                                journey_token:\n",
      "                                  type: string\n",
      "                                multi_environment_config_notes:\n",
      "                                  type: string\n",
      "                                multi_environment_config_token:\n",
      "                                  type: string\n",
      "                                workflows:\n",
      "                                  description: 'List of workflows that have been configured\n",
      "                                    as part of this Multi-Environment Configuration.\n",
      "\n",
      "                                    Workflows will either have an outcome or a list\n",
      "                                    of configured services.\n",
      "\n",
      "                                    '\n",
      "                                  items:\n",
      "                                    properties:\n",
      "                                      configured_services:\n",
      "                                        items:\n",
      "                                          properties:\n",
      "                                            credentials_description:\n",
      "                                              type: string\n",
      "                                            has_credentials:\n",
      "                                              description: True if this service has\n",
      "                                                been configured with test credentials,\n",
      "                                                false otherwise.\n",
      "                                              type: boolean\n",
      "                                            sandbox:\n",
      "                                              description: True if this service has\n",
      "                                                been configured to run in Alloy's\n",
      "                                                sandbox environment, false otherwise.\n",
      "                                              type: boolean\n",
      "                                            service_name:\n",
      "                                              type: string\n",
      "                                          type: object\n",
      "                                        type: array\n",
      "                                      outcome:\n",
      "                                        description: The outcome that all workflow\n",
      "                                          nodes using this workflow will be decisioned\n",
      "                                          to.\n",
      "                                        type: string\n",
      "                                      workflow_name:\n",
      "                                        type: string\n",
      "                                      workflow_node_type:\n",
      "                                        description: The type of node this workflow\n",
      "                                          is used as, for example Step Up\n",
      "                                        type: string\n",
      "                                      workflow_public_version:\n",
      "                                        type: number\n",
      "                                      workflow_token:\n",
      "                                        type: string\n",
      "                                    type: object\n",
      "                                  type: array\n",
      "                              type: object\n",
      "                            description: If the application has been created with\n",
      "                              a Multi-Environment Configuration, the details will\n",
      "                              be included here.\n",
      "                          rerun:\n",
      "                            description: Rerun information\n",
      "                            properties:\n",
      "                              initiated_by:\n",
      "                                enum:\n",
      "                                - api\n",
      "                                - dashboard\n",
      "                                type: string\n",
      "                              previous_journey_application_token:\n",
      "                                type: string\n",
      "                              root_external_group_id:\n",
      "                                type: string\n",
      "                              root_journey_application_token:\n",
      "                                type: string\n",
      "                            type: object\n",
      "                        type: object\n",
      "                      _links:\n",
      "                        properties:\n",
      "                          self:\n",
      "                            properties:\n",
      "                              href:\n",
      "                                description: GET route for the Application\n",
      "                                type: string\n",
      "                            type: object\n",
      "                        type: object\n",
      "                      archived_at:\n",
      "                        type: string\n",
      "                      closed_at:\n",
      "                        type: integer\n",
      "                      complete_outcome:\n",
      "                        type: string\n",
      "                      created_at:\n",
      "                        type: integer\n",
      "                      external_group_id:\n",
      "                        type: string\n",
      "                      is_archived:\n",
      "                        type: boolean\n",
      "                      is_part_of_shadow_test:\n",
      "                        description: indicates if the application is a part of a shadow\n",
      "                          test. This value is true for both the parent applications\n",
      "                          that trigger the generation of the shadow applications,\n",
      "                          as well as the shadow applications.\n",
      "                        type: boolean\n",
      "                      is_rerun:\n",
      "                        type: boolean\n",
      "                      is_shadow_app:\n",
      "                        description: indicates if the application was generated for\n",
      "                          a shadow test. This value is false for the parent applications\n",
      "                          that trigger the generation of the shadow applications.\n",
      "                        type: boolean\n",
      "                      journey_application_status:\n",
      "                        description: derived from the `status` and `complete_outcome`,\n",
      "                          this value represents a simplified display status, as seen\n",
      "                          on the Journey Application Queue and Journey Application\n",
      "                          pages.\n",
      "                        type: string\n",
      "                      journey_application_token:\n",
      "                        type: string\n",
      "                      sandbox:\n",
      "                        type: boolean\n",
      "                      status:\n",
      "                        enum:\n",
      "                        - completed\n",
      "                        - data_request\n",
      "                        - error\n",
      "                        - expired\n",
      "                        - pending_action\n",
      "                        - pending_additional_entities\n",
      "                        - pending_documents\n",
      "                        - pending_journey_application_review\n",
      "                        - pending_reconciliation\n",
      "                        - pending_step_up\n",
      "                        - pending_workflow_service\n",
      "                        - running\n",
      "                        - waiting_review\n",
      "                        type: string\n",
      "                      terminal_reconciliation_output:\n",
      "                        allOf:\n",
      "                        - properties: *id002\n",
      "                          type: object\n",
      "                        description: Data aggregated from the output of the terminal\n",
      "                          reconciliation evaluation\n",
      "                        type: object\n",
      "                      updated_at:\n",
      "                        type: integer\n",
      "                    type: object\n",
      "          description: Success\n",
      "      summary: Create Journey Application\n",
      "      tags:\n",
      "      - Journeys\n",
      "security:\n",
      "- oauth2: []\n",
      "- basic: []\n",
      "servers:\n",
      "- description: Public documentation website endpoint\n",
      "  url: https://demo-qasandbox.alloy.co/v1\n",
      "tags:\n",
      "- description: A Journey is a decision configuration that allows you to run multiple\n",
      "    workflows.\n",
      "  name: Journeys\n",
      "x-readme:\n",
      "  explorer-enabled: true\n",
      "  proxy-enabled: true\n",
      "  samples-enabled: true\n",
      "\n"
     ]
    }
   ],
   "source": [
    "relevant_docs = retriever.invoke(query)\n",
    "print(relevant_docs[0].page_content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b60f5f5-c76c-42bb-8b25-47f46b279827",
   "metadata": {},
   "source": [
    "### 💡 Since we are deleting the components from OpenAPI spec, it loses context about security requirements\n",
    "\n",
    "### 👉 Preserve components.securitySchemes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "0b68c95a-cdf4-47b9-8fcb-8446ac086746",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "72\n"
     ]
    }
   ],
   "source": [
    "import yaml\n",
    "import jsonref\n",
    "from jsonref import replace_refs\n",
    "from langchain_core.documents.base import Document\n",
    "from copy import deepcopy\n",
    "from pprint import pprint\n",
    "\n",
    "with open(\"alloy.com.yaml\") as f:\n",
    "    spec = f.read()\n",
    "\n",
    "def chunk_openapi_by_operation(openapi: str):\n",
    "    parsed = yaml.safe_load(openapi)\n",
    "\n",
    "    operations: (str, str) = []\n",
    "    # 1) list all operations by (path, HTTP method)\n",
    "    for path, methods in parsed['paths'].items():\n",
    "        for method in methods.keys():\n",
    "            # if method is not an HTTP method then skip\n",
    "            if method.lower() not in ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace']:\n",
    "                continue\n",
    "            operations.append((path, method))\n",
    "\n",
    "    # 2) create a chunk for every operation\n",
    "\n",
    "    # 2.a) Dereference entire OpenAPI Spec\n",
    "    dereferenced = replace_refs(parsed, lazy_load=False)\n",
    "\n",
    "    chunks = []\n",
    "    for operation in operations:\n",
    "        path = operation[0]\n",
    "        method = operation[1]\n",
    "        chunk = deepcopy(dereferenced)\n",
    "        if 'tags' in chunk['paths'][operation[0]][operation[1]]:\n",
    "            tags = chunk['paths'][operation[0]][operation[1]]['tags']\n",
    "\n",
    "        # first tag if possible\n",
    "        if tags:\n",
    "            tag_name = tags[0]\n",
    "\n",
    "        # delete all tags on OAS except tag for this operation\n",
    "        while len(chunk['tags']) > 1:\n",
    "            for i in range(len(chunk['tags']) - 1, -1, -1):\n",
    "                if chunk['tags'][i]['name'] != tag_name:\n",
    "                    chunk['tags'].pop(i)\n",
    "\n",
    "        if \"summary\" in chunk['paths'][path][method]:\n",
    "            summary = chunk['paths'][path][method]['summary']\n",
    "        else:\n",
    "            summary = \"\"\n",
    "\n",
    "        if \"description\" in chunk['paths'][path][method]:\n",
    "            description = chunk['paths'][path][method]['description']\n",
    "        else:\n",
    "            description = \"\"\n",
    "\n",
    "        # delete other operations\n",
    "        for other_operation in operations:\n",
    "            if other_operation[0] == operation[0]:\n",
    "                continue\n",
    "            if other_operation[0] in chunk['paths']:\n",
    "                del chunk['paths'][other_operation[0]]\n",
    "\n",
    "        # delete empty paths\n",
    "        for path in chunk['paths'].keys():\n",
    "            if not chunk['paths'][path]:\n",
    "                del chunk['paths'][path]\n",
    "\n",
    "        # delete other operations under same path\n",
    "        keys = list(chunk['paths'][operation[0]].keys())\n",
    "        for method in keys:\n",
    "            if operation[1] == method:\n",
    "                continue\n",
    "            del chunk['paths'][operation[0]][method]\n",
    "\n",
    "        # delete all components besides securitySchemes (should be inlined from 2.a)\n",
    "        if \"components\" in chunk:\n",
    "            for key in chunk[\"components\"]:\n",
    "                if key == \"securitySchemes\":\n",
    "                    continue\n",
    "                del chunk['components'][key]\n",
    "        \n",
    "        chunks.append(({\n",
    "            \"path\": operation[0],\n",
    "            \"method\": operation[1],\n",
    "            \"openapi\": yaml.dump(chunk),\n",
    "            \"tag\": tag_name,\n",
    "            \"summary\": summary,\n",
    "            \"description\": description\n",
    "        }))\n",
    "    return list(map(lambda chunk: Document(page_content=chunk[\"openapi\"], metadata={\n",
    "        \"path\": chunk[\"path\"],\n",
    "        \"method\": chunk[\"method\"],\n",
    "        \"tag\": chunk[\"tag\"],\n",
    "        \"summary\": chunk[\"summary\"],\n",
    "        \"description\": chunk[\"description\"]\n",
    "    }), chunks))\n",
    "chunks = chunk_openapi_by_operation(spec)\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "print(len(chunks))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "2b046bc5-c220-48bb-a3d1-6717a15da52e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# reset chroma DB\n",
    "from langchain_community.vectorstores.chroma import Chroma\n",
    "\n",
    "Chroma().delete_collection()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "b90e946c-fe06-4943-8bd1-ec56941275f4",
   "metadata": {
    "vscode": {
     "languageId": "plaintext"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.chains.query_constructor.base import AttributeInfo\n",
    "from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
    "from langchain_community.vectorstores.chroma import Chroma\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "import os\n",
    "\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "\n",
    "query = \"How do I create a journey application in Python?\"\n",
    "\n",
    "chat = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0, model_kwargs={\"seed\": 0})\n",
    "\n",
    "# Reset the collection to remove embeddings from previous runs\n",
    "# text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)\n",
    "# splits = text_splitter.split_documents(chunks)\n",
    "vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "15cf3eb4-429e-4de2-9c4d-22329e3faf50",
   "metadata": {},
   "outputs": [],
   "source": [
    "metadata_field_info = [\n",
    "    AttributeInfo(\n",
    "        name=\"path\",\n",
    "        description=\"The subpath for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"method\",\n",
    "        description=\"The HTTP Method for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"tag\",\n",
    "        description=\"The logical grouping for this API operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"summary\",\n",
    "        description=\"A short description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"description\",\n",
    "        description=\"A more detailed description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "]\n",
    "document_content_description = \"The pruned OpenAPI specification which includes only the relevant information for a particular operation in the OpenAPI specification.\"\n",
    "\n",
    "# Dylan: really stupid, but I had to upgrade langchain to get this to work for some reason\n",
    "retriever = SelfQueryRetriever.from_llm(\n",
    "    chat, vectorstore, document_content_description, metadata_field_info, verbose=True, search_kwargs={\"k\": 4}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "1fbca1a3-a9d5-42c1-bd87-15457b81e688",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_id: 626c513d1c9b07002812708b\n",
      "components:\n",
      "  securitySchemes:\n",
      "    basic:\n",
      "      description: HTTP basic authorization using a workflow token and secret\n",
      "      scheme: Basic\n",
      "      type: http\n",
      "    oauth2:\n",
      "      description: Oauth2 using a workflow token and secret to generate a bearer token\n",
      "      flows:\n",
      "        clientCredentials:\n",
      "          tokenUrl: /oauth/bearer\n",
      "      type: oauth2\n",
      "      x-default: viSRrSuUJEid8u0l3dyRTj5ATsWpHX9ShD51TH3j\n",
      "info:\n",
      "  description: hey hey hey, it's the Alloy API!\n",
      "  title: Alloy API\n",
      "  version: 1.0.0\n",
      "openapi: 3.0.0\n",
      "paths:\n",
      "  /journeys/{journey_token}/applications:\n",
      "    post:\n",
      "      description: 'Create a journey application for one or more entities.\n",
      "\n",
      "        '\n",
      "      requestBody:\n",
      "        content:\n",
      "          application/json:\n",
      "            schema:\n",
      "              properties:\n",
      "                do_await_additional_entities:\n",
      "                  default: false\n",
      "                  description: 'If this value is true, additional entities can be\n",
      "                    sent after this request by using the PUT endpoint that updates\n",
      "                    a journey application.\n",
      "\n",
      "\n",
      "                    The journey application will not complete until the parameter\n",
      "                    `has_finished_sending_additional_entities` is sent with the value\n",
      "                    `true` to the PUT endpoint.\n",
      "\n",
      "                    '\n",
      "                  example: false\n",
      "                  type: boolean\n",
      "                entities:\n",
      "                  description: 'List of entities to be processed in this Application.\n",
      "\n",
      "                    '\n",
      "                  example:\n",
      "                  - branch_name: persons\n",
      "                    data:\n",
      "                      addresses:\n",
      "                      - city: New York\n",
      "                        country_code: US\n",
      "                        line_1: 41 E. 11th\n",
      "                        line_2: 2nd floor\n",
      "                        postal_code: 10003\n",
      "                        state: NY\n",
      "                        type: primary\n",
      "                      birth_date: '1990-01-25'\n",
      "                      document_ssn: 111223333\n",
      "                      email_address: john@alloy.com\n",
      "                      ip_address_v4: 42.206.213.70\n",
      "                      meta:\n",
      "                        user_type: vip\n",
      "                      name_first: John\n",
      "                      name_last: Doe\n",
      "                      name_middle: Franklin\n",
      "                      phone_number: 8443825569\n",
      "                    entity_type: person\n",
      "                    external_entity_id: my_system_entity_id_123\n",
      "                  - branch_name: businesses\n",
      "                    data:\n",
      "                      addresses:\n",
      "                      - city: New York\n",
      "                        country_code: US\n",
      "                        line_1: 41 E. 11th\n",
      "                        line_2: 2nd floor\n",
      "                        postal_code: 10003\n",
      "                        state: NY\n",
      "                        type: business_primary\n",
      "                      business_federal_ein: 122334455\n",
      "                      business_name: Acme Corporation\n",
      "                      business_phone_number: 111222333\n",
      "                      business_website: https://www.acmeco.com/\n",
      "                      meta:\n",
      "                        sic_code: 1531\n",
      "                      representatives:\n",
      "                      - addresses:\n",
      "                        - city: New York\n",
      "                          country_code: US\n",
      "                          line_1: 41 E. 11th\n",
      "                          line_2: 2nd floor\n",
      "                          postal_code: 10003\n",
      "                          state: NY\n",
      "                          type: primary\n",
      "                        birth_date: '1990-01-25'\n",
      "                        document_ssn: 111223333\n",
      "                        email_address: john@alloy.com\n",
      "                        name_first: John\n",
      "                        name_last: Doe\n",
      "                        name_middle: Franklin\n",
      "                        phone_number: 8443825569\n",
      "                        type: principal_owner\n",
      "                    entity_type: business\n",
      "                    external_entity_id: my_system_entity_id_345\n",
      "                  items:\n",
      "                    anyOf:\n",
      "                    - allOf:\n",
      "                      - properties:\n",
      "                          data:\n",
      "                            description: 'Contains the fields for each input attribute\n",
      "                              of each workflow in the journey that is expected to\n",
      "                              be processed for the entity.\n",
      "\n",
      "                              '\n",
      "                            properties:\n",
      "                              addresses:\n",
      "                                description: 'List of addresses for the given entity.\n",
      "\n",
      "                                  '\n",
      "                                items:\n",
      "                                  description: Full address for a person entity\n",
      "                                  properties: &id001\n",
      "                                    city:\n",
      "                                      example: New York\n",
      "                                      type: string\n",
      "                                    country_code:\n",
      "                                      example: US\n",
      "                                      type: string\n",
      "                                    line_1:\n",
      "                                      example: 41 E. 11th\n",
      "                                      type: string\n",
      "                                    line_2:\n",
      "                                      example: 2nd floor\n",
      "                                      type: string\n",
      "                                    postal_code:\n",
      "                                      example: 10003\n",
      "                                      type: string\n",
      "                                    state:\n",
      "                                      example: NY\n",
      "                                      type: string\n",
      "                                    type:\n",
      "                                      description: Allowed values are `\"primary\"`,\n",
      "                                        `\"secondary\"`, `\"previous\"`, `\"mailing\"`,\n",
      "                                        `\"shipping\"`, `\"service\"`, `\"other\"`\n",
      "                                      example: primary\n",
      "                                      type: string\n",
      "                                  type: object\n",
      "                                type: array\n",
      "                              birth_date:\n",
      "                                example: '1990-01-25'\n",
      "                                type: string\n",
      "                              document_id_card:\n",
      "                                description: ID card number\n",
      "                                example: 1122334455\n",
      "                                type: string\n",
      "                              document_license:\n",
      "                                description: U.S. issued driver's license number\n",
      "                                example: 111222333\n",
      "                                type: string\n",
      "                              document_national_id:\n",
      "                                description: National ID number for a non-US person\n",
      "                                  entity.\n",
      "                                example: 111223333\n",
      "                                type: string\n",
      "                              document_passport:\n",
      "                                description: Passport number\n",
      "                                example: 123456789\n",
      "                                type: string\n",
      "                              document_ssn:\n",
      "                                description: Social Security number.\n",
      "                                example: 111223333\n",
      "                                type: string\n",
      "                              email_address:\n",
      "                                example: john@alloy.com\n",
      "                                type: string\n",
      "                              gender:\n",
      "                                example: male\n",
      "                                type: string\n",
      "                              ip_address_v4:\n",
      "                                example: 42.206.213.70\n",
      "                                type: string\n",
      "                              meta:\n",
      "                                description: Any additional metadata to be accessed\n",
      "                                  for decisioning or review purposes that are not\n",
      "                                  sent to a data service can be referenced here.\n",
      "                                example:\n",
      "                                  user_type: vip\n",
      "                                type: object\n",
      "                              name_first:\n",
      "                                example: John\n",
      "                                type: string\n",
      "                              name_last:\n",
      "                                example: Doe\n",
      "                                type: string\n",
      "                              name_middle:\n",
      "                                example: Franklin\n",
      "                                type: string\n",
      "                              phone_number:\n",
      "                                example: 8443825569\n",
      "                                type: string\n",
      "                            type: object\n",
      "                          external_entity_id:\n",
      "                            description: 'The value used on client''s own system to\n",
      "                              identify the entity.\n",
      "\n",
      "\n",
      "                              If an entity associated with the value passed in already\n",
      "                              exists, then the entity application processes for that\n",
      "                              entity. Otherwise, a new entity is created and associated\n",
      "                              with the value passed in.\n",
      "\n",
      "\n",
      "                              This parameter is optional, but strongly encouraged.\n",
      "\n",
      "                              '\n",
      "                            example: my_system_entity_id_123\n",
      "                            type: string\n",
      "                        required:\n",
      "                        - data\n",
      "                        type: object\n",
      "                      - properties:\n",
      "                          branch_name:\n",
      "                            default: persons\n",
      "                            description: 'This value is required for journeys with\n",
      "                              multiple branches. It must match a journey branch configured\n",
      "                              from the start node. It is used to determine\n",
      "\n",
      "                              which steps the entity will be required to complete.\n",
      "\n",
      "                              '\n",
      "                            example: my_person_branch_name\n",
      "                            type: string\n",
      "                          entity_token:\n",
      "                            description: 'The token associated with an existing entity.\n",
      "\n",
      "\n",
      "                              By passing a value for this field, the entity application\n",
      "                              processes for the existing entity associated with the\n",
      "                              token.\n",
      "\n",
      "                              '\n",
      "                            example: P-1GoQALm40nPQSp7UVTJS\n",
      "                            type: string\n",
      "                          entity_type:\n",
      "                            default: person\n",
      "                            description: If left blank, defaults to `\"person\"`.\n",
      "                            enum:\n",
      "                            - person\n",
      "                            - business\n",
      "                            example: person\n",
      "                            type: string\n",
      "                        type: object\n",
      "                    - allOf:\n",
      "                      - properties:\n",
      "                          data:\n",
      "                            description: 'Contains the fields for each input attribute\n",
      "                              of each workflow in the journey that is expected to\n",
      "                              be processed for the entity.\n",
      "\n",
      "                              '\n",
      "                            properties:\n",
      "                              addresses:\n",
      "                                description: 'List of addresses for the given entity.\n",
      "\n",
      "                                  '\n",
      "                                items:\n",
      "                                  description: Full address for a business entity\n",
      "                                  properties:\n",
      "                                    city:\n",
      "                                      example: New York\n",
      "                                      type: string\n",
      "                                    country_code:\n",
      "                                      example: US\n",
      "                                      type: string\n",
      "                                    line_1:\n",
      "                                      example: 41 E. 11th\n",
      "                                      type: string\n",
      "                                    line_2:\n",
      "                                      example: 2nd floor\n",
      "                                      type: string\n",
      "                                    postal_code:\n",
      "                                      example: 10003\n",
      "                                      type: string\n",
      "                                    state:\n",
      "                                      example: NY\n",
      "                                      type: string\n",
      "                                    type:\n",
      "                                      description: Allowed values are `\"business_primary\"`,\n",
      "                                        `\"business_secondary\"`, `\"business_previous\"`\n",
      "                                      example: business_primary\n",
      "                                      type: string\n",
      "                                  type: object\n",
      "                                type: array\n",
      "                              business_federal_ein:\n",
      "                                description: Business federal employer ID number for\n",
      "                                  US business entities.\n",
      "                                example: 122334455\n",
      "                                type: string\n",
      "                              business_name:\n",
      "                                example: Acme Corporation\n",
      "                                type: string\n",
      "                              business_phone_number:\n",
      "                                description: Business phone number.\n",
      "                                example: 111222333\n",
      "                                type: string\n",
      "                              business_registry_id:\n",
      "                                description: Business registry ID number for non-US\n",
      "                                  business entities.\n",
      "                                example: 122334455\n",
      "                                type: string\n",
      "                              business_website:\n",
      "                                description: Business website.\n",
      "                                example: https://www.acmeco.com/\n",
      "                                type: string\n",
      "                              meta:\n",
      "                                description: Any additional metadata to be accessed\n",
      "                                  for decisioning or review purposes that are not\n",
      "                                  sent to a data service can be referenced here.\n",
      "                                example:\n",
      "                                  sic_code: 1531\n",
      "                                type: object\n",
      "                              representatives:\n",
      "                                description: List of ultimate beneficial owners associated\n",
      "                                  to the business.\n",
      "                                items:\n",
      "                                  description: Ultimate beneficial owners associated\n",
      "                                    to the business.\n",
      "                                  properties:\n",
      "                                    addresses:\n",
      "                                      description: 'List of addresses for the given\n",
      "                                        entity.\n",
      "\n",
      "                                        '\n",
      "                                      items:\n",
      "                                        description: Full address for a person entity\n",
      "                                        properties: *id001\n",
      "                                        type: object\n",
      "                                      type: array\n",
      "                                    birth_date:\n",
      "                                      example: '1990-01-25'\n",
      "                                      type: string\n",
      "                                    document_ssn:\n",
      "                                      description: Social Security number\n",
      "                                      example: 111223333\n",
      "                                      type: string\n",
      "                                    email_address:\n",
      "                                      example: john@alloy.com\n",
      "                                      type: string\n",
      "                                    name_first:\n",
      "                                      example: John\n",
      "                                      type: string\n",
      "                                    name_last:\n",
      "                                      example: Doe\n",
      "                                      type: string\n",
      "                                    name_middle:\n",
      "                                      example: Franklin\n",
      "                                      type: string\n",
      "                                    phone_number:\n",
      "                                      example: 8443825569\n",
      "                                      type: string\n",
      "                                    type:\n",
      "                                      description: Allowed values are `\"principal_owner\"`\n",
      "                                        or `\"authorized_signer\"`.\n",
      "                                      example: principal_owner\n",
      "                                      type: string\n",
      "                                  type: object\n",
      "                                type: array\n",
      "                            type: object\n",
      "                          external_entity_id:\n",
      "                            description: 'The value used on client''s own system to\n",
      "                              identify the entity.\n",
      "\n",
      "                              If an entity associated with the value passed in already\n",
      "                              exists, then the entity application processes for that\n",
      "                              entity. Otherwise, a new entity is created and associated\n",
      "                              with the value passed in.\n",
      "\n",
      "                              This parameter is optional, but strongly encouraged.\n",
      "\n",
      "                              '\n",
      "                            example: my_system_entity_id_345\n",
      "                            type: string\n",
      "                        required:\n",
      "                        - data\n",
      "                        type: object\n",
      "                      - properties:\n",
      "                          branch_name:\n",
      "                            default: businesses\n",
      "                            description: 'This value is required for journeys with\n",
      "                              multiple branches. It must match a journey branch configured\n",
      "                              from the start node. It is used to determine\n",
      "\n",
      "                              which steps the entity will be required to complete.\n",
      "\n",
      "                              '\n",
      "                            example: my_business_branch_name\n",
      "                            type: string\n",
      "                          entity_token:\n",
      "                            description: 'The token associated with an existing entity.\n",
      "\n",
      "                              By passing a value for this field, the entity application\n",
      "                              processes for the existing entity associated with the\n",
      "                              token.\n",
      "\n",
      "                              '\n",
      "                            example: B-4vaKI3CAgBvpdLpMifon\n",
      "                            type: string\n",
      "                          entity_type:\n",
      "                            default: business\n",
      "                            description: If left blank, defaults to `\"person\"`.\n",
      "                            example: business\n",
      "                            type: string\n",
      "                        type: object\n",
      "                      title: Business Entity\n",
      "                  type: array\n",
      "                external_group_id:\n",
      "                  description: 'Optional, but if you have an identifier in your system\n",
      "                    that represents the entire Application\n",
      "\n",
      "                    (meaning, all the person or persons applying for this product),\n",
      "                    include it here. This identifier must be unique.\n",
      "\n",
      "                    '\n",
      "                  example: my_system_group_id_456\n",
      "                  type: string\n",
      "                external_product_id:\n",
      "                  description: 'Optional, but if you have an identifier in your system\n",
      "                    for the product that this\n",
      "\n",
      "                    application is applying for, include it here.\n",
      "\n",
      "                    '\n",
      "                  example: my_system_product_id_789\n",
      "                  type: string\n",
      "              required:\n",
      "              - entities\n",
      "      responses:\n",
      "        '201':\n",
      "          content:\n",
      "            application/json:\n",
      "              schema:\n",
      "                oneOf:\n",
      "                - allOf:\n",
      "                  - title: When header `alloy-journey-override-sync` is set to `true`\n",
      "                  - properties:\n",
      "                      _links:\n",
      "                        properties:\n",
      "                          self:\n",
      "                            properties:\n",
      "                              href:\n",
      "                                description: GET route for the Application\n",
      "                                example: /v1/journeys/J-Kq8jlFcA4veeHCtt823h/applications/JA-LS0GHKjDNhY6dGlvYxxH\n",
      "                                type: string\n",
      "                            type: object\n",
      "                        type: object\n",
      "                      journey_application_token:\n",
      "                        example: JA-LS0GHKjDNhY6dGlvYxxH\n",
      "                        type: string\n",
      "                    type: object\n",
      "                - allOf:\n",
      "                  - title: When header `alloy-journey-override-sync` is set to `false`\n",
      "                      or not passed in\n",
      "                  - example:\n",
      "                      _embedded:\n",
      "                        child_entities:\n",
      "                        - created: '2021-10-12T20:38:26.493Z'\n",
      "                          entity_application_outcome: approved\n",
      "                          entity_application_status: completed\n",
      "                          entity_application_token: EA-GessHRonFRTSXCmErk7J\n",
      "                          external_entity_identifier: external_entity_id123\n",
      "                          name: John Doe\n",
      "                          token: P-tZOLIOQGVxfixICuvkS0\n",
      "                          type: person\n",
      "                        entity:\n",
      "                          external_entity_identifier: null\n",
      "                          name: null\n",
      "                          token: G-wBdsvC7hA84j7p4PTVcD\n",
      "                          type: group\n",
      "                        entity_applications:\n",
      "                        - entity_application_outcome: approved\n",
      "                          entity_application_status: completed\n",
      "                          entity_application_status_details: null\n",
      "                          entity_application_token: EA-GessHRonFRTSXCmErk7J\n",
      "                          entity_token: P-tZOLIOQGVxfixICuvkS0\n",
      "                          output:\n",
      "                            matrix_models:\n",
      "                              my_matrix:\n",
      "                                matrix_model_public_version: 5\n",
      "                                matrix_model_token: MM-Z37VkZwHMbnzhLJM7ZlX\n",
      "                                name: my_matrix\n",
      "                                result: 15\n",
      "                                status: executed\n",
      "                                x_bucket: 1\n",
      "                                x_value: 1000\n",
      "                                y_bucket: 0\n",
      "                                y_value: 300\n",
      "                            outcome_reasons:\n",
      "                            - name: Fraud Risk\n",
      "                              type: null\n",
      "                            output_attributes:\n",
      "                              income_calculation: 98000\n",
      "                            tags:\n",
      "                            - fraud_tag\n",
      "                            - Fraud Risk\n",
      "                        events:\n",
      "                        - _embedded:\n",
      "                            node:\n",
      "                              config:\n",
      "                                workflow_token: vUr2Fs1y8Qiz1a79kNJk1dk7EfYUAJRK\n",
      "                                workflow_version_id: 1\n",
      "                              id: '1632850505316'\n",
      "                              name: null\n",
      "                              type: workflow\n",
      "                          _links: {}\n",
      "                          entity_token: null\n",
      "                          timestamp: 1634059958414\n",
      "                          type: started_application\n",
      "                        - _embedded:\n",
      "                            node:\n",
      "                              config:\n",
      "                                workflow_token: vUr2Fs1y8Qiz1a79kNJk1dk7EfYUAJRK\n",
      "                                workflow_version_id: 1\n",
      "                              id: '1632850505316'\n",
      "                              name: null\n",
      "                              type: workflow\n",
      "                          _links:\n",
      "                            evaluation:\n",
      "                              href: /v1/evaluations/L-Vn9uOp0ZyYvjDL1t3Sd7\n",
      "                          entity_token: null\n",
      "                          evaluation_token: L-Vn9uOp0ZyYvjDL1t3Sd7\n",
      "                          sdk_config:\n",
      "                            documents:\n",
      "                            - passport\n",
      "                            selfie: true\n",
      "                          timestamp: 1634059958531\n",
      "                          type: started_evaluation\n",
      "                        - _embedded:\n",
      "                            node:\n",
      "                              config:\n",
      "                                workflow_token: vUr2Fs1y8Qiz1a79kNJk1dk7EfYUAJRK\n",
      "                                workflow_version_id: 1\n",
      "                              id: '1632850505316'\n",
      "                              name: null\n",
      "                              type: workflow\n",
      "                          _links:\n",
      "                            evaluation:\n",
      "                              href: /v1/evaluations/L-Vn9uOp0ZyYvjDL1t3Sd7\n",
      "                          entity_token: P-tZOLIOQGVxfixICuvkS0\n",
      "                          evaluation_token: L-Vn9uOp0ZyYvjDL1t3Sd7\n",
      "                          outcome: Approved\n",
      "                          timestamp: 1634059960557\n",
      "                          type: completed_evaluation\n",
      "                        - _embedded:\n",
      "                            node:\n",
      "                              config:\n",
      "                                outcome: Approved\n",
      "                              id: '1633639581306'\n",
      "                              name: null\n",
      "                              type: outcome\n",
      "                          _links: {}\n",
      "                          entity_token: P-tZOLIOQGVxfixICuvkS0\n",
      "                          outcome: Approved\n",
      "                          timestamp: 1634059961453\n",
      "                          type: completed_application\n",
      "                        journey:\n",
      "                          _links:\n",
      "                            callback_by_entity_application_token:\n",
      "                              href: /v1/journeys/J-rTE9lsgkluEMB6pWp6Y5/applications/JA-iLh1wxtrpfGuncHQVcwK/nodes/97b927fe-637b-42be-aa70-1e998ad57bb3\n",
      "                            self:\n",
      "                              href: /v1/journeys/J-qDydegaMK8otdsRYquOR\n",
      "                          journey_name: ''\n",
      "                          journey_token: J-qDydegaMK8otdsRYquOR\n",
      "                          journey_type: application\n",
      "                        rerun:\n",
      "                          initiated_by: dashboard\n",
      "                          previous_journey_application_token: JA-zvtpApEGBnmKepPwygBx\n",
      "                          root_external_group_id: null\n",
      "                          root_journey_application_token: JA-zvtpApEGBnmKepPwygBx\n",
      "                      _links:\n",
      "                        self:\n",
      "                          href: /v1/journeys/J-qDydegaMK8otdsRYquOR/applications/JA-ddjP31DhduTI334Cs3uT\n",
      "                      annual_interest_rate: '70'\n",
      "                      closed_at: 1634059961464\n",
      "                      complete_outcome: Approved\n",
      "                      created_at: 1634059958368\n",
      "                      credit_limit: '42'\n",
      "                      is_rerun: true\n",
      "                      journey_application_token: JA-ddjP31DhduTI334Cs3uT\n",
      "                      recent_outcome: Approved\n",
      "                      sandbox: false\n",
      "                      status: completed\n",
      "                      terminal_reconciliation_output:\n",
      "                        matrix_models:\n",
      "                          my_matrix:\n",
      "                            matrix_model_public_version: 5\n",
      "                            matrix_model_token: MM-Z37VkZwHMbnzhLJM7ZlX\n",
      "                            name: my_matrix\n",
      "                            result: 15\n",
      "                            status: executed\n",
      "                            x_bucket: 1\n",
      "                            x_value: 1000\n",
      "                            y_bucket: 0\n",
      "                            y_value: 300\n",
      "                        outcome_reasons:\n",
      "                        - name: Fraud Risk\n",
      "                          type: null\n",
      "                        output_attributes:\n",
      "                          income_calculation: 98000\n",
      "                        tags:\n",
      "                        - fraud_tag\n",
      "                        - Fraud Risk\n",
      "                      updated_at: 1634059961458\n",
      "                    properties:\n",
      "                      _embedded:\n",
      "                        properties:\n",
      "                          child_entities:\n",
      "                            items:\n",
      "                              properties:\n",
      "                                created:\n",
      "                                  type: string\n",
      "                                entity_application_branch_name:\n",
      "                                  type: string\n",
      "                                entity_application_outcome:\n",
      "                                  type: string\n",
      "                                entity_application_status:\n",
      "                                  type: string\n",
      "                                entity_application_token:\n",
      "                                  type: string\n",
      "                                external_entity_identifier:\n",
      "                                  type: string\n",
      "                                name:\n",
      "                                  type: string\n",
      "                                sandbox_persona_name:\n",
      "                                  description: When applicable, name of sandbox persona\n",
      "                                    used for this child entity\n",
      "                                  type: string\n",
      "                                token:\n",
      "                                  type: string\n",
      "                                type:\n",
      "                                  type: string\n",
      "                              type: object\n",
      "                            type: array\n",
      "                          entity:\n",
      "                            description: The journey application entity\n",
      "                            properties:\n",
      "                              external_entity_identifier:\n",
      "                                type: string\n",
      "                              name:\n",
      "                                type: string\n",
      "                              token:\n",
      "                                type: string\n",
      "                              type:\n",
      "                                type: string\n",
      "                            type: object\n",
      "                          entity_applications:\n",
      "                            items:\n",
      "                              properties:\n",
      "                                entity_application_outcome:\n",
      "                                  type: string\n",
      "                                entity_application_status:\n",
      "                                  type: string\n",
      "                                entity_application_status_details:\n",
      "                                  description: Additional details for applications\n",
      "                                    that have status `data_request`\n",
      "                                  properties:\n",
      "                                    optional:\n",
      "                                      items:\n",
      "                                        properties:\n",
      "                                          description:\n",
      "                                            type: string\n",
      "                                          key:\n",
      "                                            type: string\n",
      "                                          regex:\n",
      "                                            type: string\n",
      "                                          type:\n",
      "                                            type: string\n",
      "                                        type: object\n",
      "                                      type: array\n",
      "                                    or:\n",
      "                                      type: string\n",
      "                                    required:\n",
      "                                      items:\n",
      "                                        properties:\n",
      "                                          description:\n",
      "                                            type: string\n",
      "                                          key:\n",
      "                                            type: string\n",
      "                                          message:\n",
      "                                            type: string\n",
      "                                          regex:\n",
      "                                            type: string\n",
      "                                          type:\n",
      "                                            type: string\n",
      "                                        type: object\n",
      "                                      type: array\n",
      "                                  type: object\n",
      "                                entity_application_token:\n",
      "                                  type: string\n",
      "                                entity_token:\n",
      "                                  type: string\n",
      "                                output:\n",
      "                                  allOf:\n",
      "                                  - properties: &id002\n",
      "                                      matrix_models:\n",
      "                                        additionalProperties:\n",
      "                                          description: NOTE the dynamic property name\n",
      "                                            refers to the name of the matrix model\n",
      "                                          properties:\n",
      "                                            matrix_model_public_version:\n",
      "                                              type: integer\n",
      "                                            matrix_model_token:\n",
      "                                              type: string\n",
      "                                            name:\n",
      "                                              type: string\n",
      "                                            result:\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                            status:\n",
      "                                              enum:\n",
      "                                              - executed\n",
      "                                              - not_executed\n",
      "                                              type: string\n",
      "                                            x_bucket:\n",
      "                                              description: x-coordinate of the matrix\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                            x_value:\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                            y_bucket:\n",
      "                                              description: y-coordinate of the matrix\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                            y_value:\n",
      "                                              nullable: true\n",
      "                                              type: number\n",
      "                                          type: object\n",
      "                                        type: object\n",
      "                                      outcome_reasons:\n",
      "                                        items:\n",
      "                                          properties:\n",
      "                                            name:\n",
      "                                              type: string\n",
      "                                            type:\n",
      "                                              enum:\n",
      "                                              - adverse_action\n",
      "                                              - null\n",
      "                                              type: string\n",
      "                                          type: object\n",
      "                                        type: array\n",
      "                                      output_attributes:\n",
      "                                        additionalProperties:\n",
      "                                          description: NOTE the dynamic property name\n",
      "                                            refers to the name of the output attribute\n",
      "                                          oneOf:\n",
      "                                          - type: string\n",
      "                                          - type: number\n",
      "                                        type: object\n",
      "                                      tags:\n",
      "                                        items:\n",
      "                                          type: string\n",
      "                                        type: array\n",
      "                                    type: object\n",
      "                                  description: Data aggregated from the outputs of\n",
      "                                    every evaluation run for the entity application\n",
      "                                  type: object\n",
      "                              type: object\n",
      "                            type: array\n",
      "                          events:\n",
      "                            description: List of journey application events, ordered\n",
      "                              chronologically. The fields displayed in the event will\n",
      "                              depend on the event type\n",
      "                            items:\n",
      "                              properties:\n",
      "                                _embedded:\n",
      "                                  properties:\n",
      "                                    node:\n",
      "                                      properties:\n",
      "                                        config:\n",
      "                                          description: Config related to the specific\n",
      "                                            node, depending on the type\n",
      "                                          type: object\n",
      "                                        id:\n",
      "                                          type: string\n",
      "                                        name:\n",
      "                                          type: string\n",
      "                                        sdk_config:\n",
      "                                          description: Settings to be read by SDK\n",
      "                                            to handle processing. Only present on\n",
      "                                            workflow node events.\n",
      "                                          properties:\n",
      "                                            documents:\n",
      "                                              items:\n",
      "                                                type: string\n",
      "                                              type: array\n",
      "                                            selfie:\n",
      "                                              type: boolean\n",
      "                                          type: object\n",
      "                                        type:\n",
      "                                          enum:\n",
      "                                          - start\n",
      "                                          - workflow\n",
      "                                          - review\n",
      "                                          - outcome\n",
      "                                          - action\n",
      "                                          - docv\n",
      "                                          type: string\n",
      "                                        workflow_name:\n",
      "                                          type: string\n",
      "                                      type: object\n",
      "                                  type: object\n",
      "                                _links:\n",
      "                                  properties:\n",
      "                                    case:\n",
      "                                      properties:\n",
      "                                        href:\n",
      "                                          type: string\n",
      "                                      type: object\n",
      "                                    evaluation:\n",
      "                                      properties:\n",
      "                                        href:\n",
      "                                          type: string\n",
      "                                      type: object\n",
      "                                  type: object\n",
      "                                entity_application_token:\n",
      "                                  type: string\n",
      "                                entity_token:\n",
      "                                  type: string\n",
      "                                error_data:\n",
      "                                  description: Additional error data populated when\n",
      "                                    available for `error` event types\n",
      "                                  properties:\n",
      "                                    application_token:\n",
      "                                      type: string\n",
      "                                    application_version_id:\n",
      "                                      type: integer\n",
      "                                    entity_token:\n",
      "                                      type: string\n",
      "                                    error:\n",
      "                                      properties:\n",
      "                                        details:\n",
      "                                          type: object\n",
      "                                        error_token:\n",
      "                                          type: string\n",
      "                                        message:\n",
      "                                          type: string\n",
      "                                        minor_code:\n",
      "                                          type: integer\n",
      "                                        type:\n",
      "                                          type: string\n",
      "                                      type: object\n",
      "                                    evaluation_token:\n",
      "                                      type: string\n",
      "                                    status_code:\n",
      "                                      type: integer\n",
      "                                    timestamp:\n",
      "                                      type: integer\n",
      "                                  type: object\n",
      "                                evaluation_token:\n",
      "                                  description: Identifying evaluation token (only\n",
      "                                    in evaluation type events)\n",
      "                                  type: string\n",
      "                                external_group_id:\n",
      "                                  type: string\n",
      "                                external_partner_id:\n",
      "                                  type: string\n",
      "                                journey_application_event_token:\n",
      "                                  type: string\n",
      "                                journey_application_token:\n",
      "                                  type: string\n",
      "                                journey_type:\n",
      "                                  enum:\n",
      "                                  - alert\n",
      "                                  - application\n",
      "                                  type: string\n",
      "                                outcome:\n",
      "                                  description: 'Populated for the following event\n",
      "                                    types: `completed_action`, `completed_application`,\n",
      "                                    `completed_branch`, `completed_evaluation`, `completed_review`,\n",
      "                                    `pending_action_expired`'\n",
      "                                  type: string\n",
      "                                reason:\n",
      "                                  type: string\n",
      "                                reasons:\n",
      "                                  items:\n",
      "                                    type: string\n",
      "                                  type: array\n",
      "                                timestamp:\n",
      "                                  type: integer\n",
      "                                type:\n",
      "                                  enum:\n",
      "                                  - application_expired\n",
      "                                  - completed_action\n",
      "                                  - completed_application\n",
      "                                  - completed_branch\n",
      "                                  - completed_evaluation\n",
      "                                  - completed_reconciliation\n",
      "                                  - completed_review\n",
      "                                  - completed_review_journey_application\n",
      "                                  - data_request_evaluation\n",
      "                                  - error\n",
      "                                  - has_finished_sending_additional_entities\n",
      "                                  - pending_action\n",
      "                                  - pending_action_expired\n",
      "                                  - pending_documents\n",
      "                                  - pending_review\n",
      "                                  - pending_step_up\n",
      "                                  - pending_workflow_service\n",
      "                                  - reached_auto_decision_node\n",
      "                                  - started_application\n",
      "                                  - started_evaluation\n",
      "                                  - started_reconciliation\n",
      "                                  type: string\n",
      "                              type: object\n",
      "                            type: array\n",
      "                          journey:\n",
      "                            properties:\n",
      "                              _links:\n",
      "                                properties:\n",
      "                                  callback_by_entity_application_token:\n",
      "                                    description: When applicable, the route to send\n",
      "                                      a PUT request to for each entity application\n",
      "                                      to resolve its current pending state\n",
      "                                    type: object\n",
      "                                  self:\n",
      "                                    properties:\n",
      "                                      href:\n",
      "                                        description: GET route for the Journey\n",
      "                                        type: string\n",
      "                                    type: object\n",
      "                                type: object\n",
      "                              journey_name:\n",
      "                                type: string\n",
      "                              journey_token:\n",
      "                                type: string\n",
      "                              journey_type:\n",
      "                                enum:\n",
      "                                - application\n",
      "                                - alert\n",
      "                                type: string\n",
      "                              journey_version_num:\n",
      "                                type: string\n",
      "                            type: object\n",
      "                          multi_environment_config:\n",
      "                            allOf:\n",
      "                            - properties:\n",
      "                                actions:\n",
      "                                  description: List of journey actions that have been\n",
      "                                    configured as part of this Multi-Environment Configuration.\n",
      "                                  items:\n",
      "                                    properties:\n",
      "                                      action_name:\n",
      "                                        type: string\n",
      "                                      action_version:\n",
      "                                        type: number\n",
      "                                      journey_action_id:\n",
      "                                        type: number\n",
      "                                      outcome:\n",
      "                                        description: The outcome that all action nodes\n",
      "                                          for this journey action will be decisioned\n",
      "                                          to.\n",
      "                                        type: string\n",
      "                                    type: object\n",
      "                                  type: array\n",
      "                                created_at:\n",
      "                                  type: string\n",
      "                                journey_name:\n",
      "                                  type: string\n",
      "                                journey_public_version:\n",
      "                                  type: number\n",
      "                                journey_token:\n",
      "                                  type: string\n",
      "                                multi_environment_config_notes:\n",
      "                                  type: string\n",
      "                                multi_environment_config_token:\n",
      "                                  type: string\n",
      "                                workflows:\n",
      "                                  description: 'List of workflows that have been configured\n",
      "                                    as part of this Multi-Environment Configuration.\n",
      "\n",
      "                                    Workflows will either have an outcome or a list\n",
      "                                    of configured services.\n",
      "\n",
      "                                    '\n",
      "                                  items:\n",
      "                                    properties:\n",
      "                                      configured_services:\n",
      "                                        items:\n",
      "                                          properties:\n",
      "                                            credentials_description:\n",
      "                                              type: string\n",
      "                                            has_credentials:\n",
      "                                              description: True if this service has\n",
      "                                                been configured with test credentials,\n",
      "                                                false otherwise.\n",
      "                                              type: boolean\n",
      "                                            sandbox:\n",
      "                                              description: True if this service has\n",
      "                                                been configured to run in Alloy's\n",
      "                                                sandbox environment, false otherwise.\n",
      "                                              type: boolean\n",
      "                                            service_name:\n",
      "                                              type: string\n",
      "                                          type: object\n",
      "                                        type: array\n",
      "                                      outcome:\n",
      "                                        description: The outcome that all workflow\n",
      "                                          nodes using this workflow will be decisioned\n",
      "                                          to.\n",
      "                                        type: string\n",
      "                                      workflow_name:\n",
      "                                        type: string\n",
      "                                      workflow_node_type:\n",
      "                                        description: The type of node this workflow\n",
      "                                          is used as, for example Step Up\n",
      "                                        type: string\n",
      "                                      workflow_public_version:\n",
      "                                        type: number\n",
      "                                      workflow_token:\n",
      "                                        type: string\n",
      "                                    type: object\n",
      "                                  type: array\n",
      "                              type: object\n",
      "                            description: If the application has been created with\n",
      "                              a Multi-Environment Configuration, the details will\n",
      "                              be included here.\n",
      "                          rerun:\n",
      "                            description: Rerun information\n",
      "                            properties:\n",
      "                              initiated_by:\n",
      "                                enum:\n",
      "                                - api\n",
      "                                - dashboard\n",
      "                                type: string\n",
      "                              previous_journey_application_token:\n",
      "                                type: string\n",
      "                              root_external_group_id:\n",
      "                                type: string\n",
      "                              root_journey_application_token:\n",
      "                                type: string\n",
      "                            type: object\n",
      "                        type: object\n",
      "                      _links:\n",
      "                        properties:\n",
      "                          self:\n",
      "                            properties:\n",
      "                              href:\n",
      "                                description: GET route for the Application\n",
      "                                type: string\n",
      "                            type: object\n",
      "                        type: object\n",
      "                      archived_at:\n",
      "                        type: string\n",
      "                      closed_at:\n",
      "                        type: integer\n",
      "                      complete_outcome:\n",
      "                        type: string\n",
      "                      created_at:\n",
      "                        type: integer\n",
      "                      external_group_id:\n",
      "                        type: string\n",
      "                      is_archived:\n",
      "                        type: boolean\n",
      "                      is_part_of_shadow_test:\n",
      "                        description: indicates if the application is a part of a shadow\n",
      "                          test. This value is true for both the parent applications\n",
      "                          that trigger the generation of the shadow applications,\n",
      "                          as well as the shadow applications.\n",
      "                        type: boolean\n",
      "                      is_rerun:\n",
      "                        type: boolean\n",
      "                      is_shadow_app:\n",
      "                        description: indicates if the application was generated for\n",
      "                          a shadow test. This value is false for the parent applications\n",
      "                          that trigger the generation of the shadow applications.\n",
      "                        type: boolean\n",
      "                      journey_application_status:\n",
      "                        description: derived from the `status` and `complete_outcome`,\n",
      "                          this value represents a simplified display status, as seen\n",
      "                          on the Journey Application Queue and Journey Application\n",
      "                          pages.\n",
      "                        type: string\n",
      "                      journey_application_token:\n",
      "                        type: string\n",
      "                      sandbox:\n",
      "                        type: boolean\n",
      "                      status:\n",
      "                        enum:\n",
      "                        - completed\n",
      "                        - data_request\n",
      "                        - error\n",
      "                        - expired\n",
      "                        - pending_action\n",
      "                        - pending_additional_entities\n",
      "                        - pending_documents\n",
      "                        - pending_journey_application_review\n",
      "                        - pending_reconciliation\n",
      "                        - pending_step_up\n",
      "                        - pending_workflow_service\n",
      "                        - running\n",
      "                        - waiting_review\n",
      "                        type: string\n",
      "                      terminal_reconciliation_output:\n",
      "                        allOf:\n",
      "                        - properties: *id002\n",
      "                          type: object\n",
      "                        description: Data aggregated from the output of the terminal\n",
      "                          reconciliation evaluation\n",
      "                        type: object\n",
      "                      updated_at:\n",
      "                        type: integer\n",
      "                    type: object\n",
      "          description: Success\n",
      "      summary: Create Journey Application\n",
      "      tags:\n",
      "      - Journeys\n",
      "security:\n",
      "- oauth2: []\n",
      "- basic: []\n",
      "servers:\n",
      "- description: Public documentation website endpoint\n",
      "  url: https://demo-qasandbox.alloy.co/v1\n",
      "tags:\n",
      "- description: A Journey is a decision configuration that allows you to run multiple\n",
      "    workflows.\n",
      "  name: Journeys\n",
      "x-readme:\n",
      "  explorer-enabled: true\n",
      "  proxy-enabled: true\n",
      "  samples-enabled: true\n",
      "\n"
     ]
    }
   ],
   "source": [
    "relevant_docs = retriever.invoke(query)\n",
    "print(relevant_docs[0].page_content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "e6eb09bb-e6f1-4389-a667-0766b4849935",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "better_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"You are a world-class solutions engineer and amazing at question-answering tasks. If you don't know the answer, just say that you don't know. Use markdown to ensure code blocks and commands are propertly formatted. Make sure to always include environment setup instructions and code blocks that are helpful for a developer to copy-paste. Always explain inputs and outputs of API requests. Be as detailed as possible. Answer the user's questions based on the below context:\\n\\n{context}\",\n",
    "        ),\n",
    "        (\n",
    "            \"user\",\n",
    "            \"{question}\"\n",
    "        )\n",
    "    ]\n",
    ")\n",
    "\n",
    "def format_docs(docs):\n",
    "    return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
    "\n",
    "rag_chain = (\n",
    "    {\"context\": retriever | format_docs, \"question\": RunnablePassthrough()}\n",
    "    | better_prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "98593211-6625-4912-8943-eda2270d7b83",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey application in Python, you will need to make an HTTP POST request to the endpoint `/journeys/{journey_token}/applications` with the necessary payload containing the entities and other relevant information. Here's a step-by-step guide on how to do this using the `requests` library in Python:\n",
       "\n",
       "1. Install the `requests` library if you haven't already. You can install it using pip:\n",
       "\n",
       "```bash\n",
       "pip install requests\n",
       "```\n",
       "\n",
       "2. Import the necessary libraries:\n",
       "\n",
       "```python\n",
       "import requests\n",
       "import json\n",
       "```\n",
       "\n",
       "3. Define the base URL and the journey token:\n",
       "\n",
       "```python\n",
       "base_url = \"https://demo-qasandbox.alloy.co/v1\"\n",
       "journey_token = \"JourneyTokenHere\"\n",
       "url = f\"{base_url}/journeys/{journey_token}/applications\"\n",
       "```\n",
       "\n",
       "4. Prepare the payload for the journey application. You can use the example payload provided in the API documentation:\n",
       "\n",
       "```python\n",
       "payload = {\n",
       "    \"do_await_additional_entities\": False,\n",
       "    \"entities\": [\n",
       "        {\n",
       "            \"branch_name\": \"persons\",\n",
       "            \"data\": {\n",
       "                \"addresses\": [\n",
       "                    {\n",
       "                        \"city\": \"New York\",\n",
       "                        \"country_code\": \"US\",\n",
       "                        \"line_1\": \"41 E. 11th\",\n",
       "                        \"line_2\": \"2nd floor\",\n",
       "                        \"postal_code\": \"10003\",\n",
       "                        \"state\": \"NY\",\n",
       "                        \"type\": \"primary\"\n",
       "                    }\n",
       "                ],\n",
       "                \"birth_date\": \"1990-01-25\",\n",
       "                \"document_ssn\": \"111223333\",\n",
       "                \"email_address\": \"john@alloy.com\",\n",
       "                \"ip_address_v4\": \"42.206.213.70\",\n",
       "                \"meta\": {\n",
       "                    \"user_type\": \"vip\"\n",
       "                },\n",
       "                \"name_first\": \"John\",\n",
       "                \"name_last\": \"Doe\",\n",
       "                \"name_middle\": \"Franklin\",\n",
       "                \"phone_number\": \"8443825569\"\n",
       "            },\n",
       "            \"entity_type\": \"person\",\n",
       "            \"external_entity_id\": \"my_system_entity_id_123\"\n",
       "        }\n",
       "    ]\n",
       "}\n",
       "```\n",
       "\n",
       "5. Make the POST request to create the journey application:\n",
       "\n",
       "```python\n",
       "headers = {\n",
       "    \"Content-Type\": \"application/json\"\n",
       "}\n",
       "\n",
       "response = requests.post(url, headers=headers, data=json.dumps(payload))\n",
       "\n",
       "if response.status_code == 201:\n",
       "    print(\"Journey application created successfully!\")\n",
       "    print(response.json())\n",
       "else:\n",
       "    print(\"Failed to create journey application.\")\n",
       "    print(response.text)\n",
       "```\n",
       "\n",
       "6. Replace `JourneyTokenHere` with the actual journey token you want to use.\n",
       "\n",
       "7. Run the Python script, and it will create a journey application based on the provided payload.\n",
       "\n",
       "This script will send a POST request to the Alloy API to create a journey application with the specified entities. Make sure to replace the placeholders with actual data before running the script."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "output = rag_chain.invoke(query)\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bef7bad8-1b53-4b3b-b062-b4351ac6b5a1",
   "metadata": {},
   "source": [
    "### 👎 The guide did not explicitly guide the user through authentication\n",
    "\n",
    "### 🤔 Maybe better prompting will do the trick"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "7e7977ce-9f29-4f2b-8c0e-1fda62cfdf9d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "better_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"\"\"You are a world-class solutions engineer and amazing at question-answering tasks. You are also a world-class API\n",
    "            integrations specialist and deeply understand OpenAPI Specification.\n",
    "            \n",
    "            You strictly follow these rules:\n",
    "            - If you don't know the answer, just say that you don't know.\n",
    "            - Use markdown to ensure code blocks and commands are propertly formatted.\n",
    "            - Make sure to always include environment setup instructions and code blocks that are helpful for a developer to copy-paste.\n",
    "            - Always explain inputs and outputs of API requests. Be as detailed as possible.\n",
    "            - When presented with an OpenAPI Specification and asked questions about it, always include necessary steps to\n",
    "            authenticate with the endpoint.\n",
    "            - When presented with multiple authentication options, make sure to guide the customer through both methods\n",
    "            \n",
    "            Answer the user's questions based on the below context:\\n\\n{context}\"\"\",\n",
    "        ),\n",
    "        (\n",
    "            \"user\",\n",
    "            \"{question}\"\n",
    "        )\n",
    "    ]\n",
    ")\n",
    "\n",
    "def format_docs(docs):\n",
    "    return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
    "\n",
    "rag_chain = (\n",
    "    {\"context\": retriever | format_docs, \"question\": RunnablePassthrough()}\n",
    "    | better_prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "5e761a20-b57a-4eaf-a7c6-b9e8cefde9f0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey application in Python using the Alloy API, you will need to make a POST request to the `/journeys/{journey_token}/applications` endpoint with the necessary payload. Here's a step-by-step guide on how to achieve this:\n",
       "\n",
       "### Prerequisites:\n",
       "- You need to have the `requests` library installed. If you don't have it installed, you can install it using pip:\n",
       "  ```bash\n",
       "  pip install requests\n",
       "  ```\n",
       "\n",
       "### Python code to create a journey application:\n",
       "```python\n",
       "import requests\n",
       "import json\n",
       "\n",
       "# Define the endpoint URL and journey token\n",
       "url = \"https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications\"\n",
       "journey_token = \"your_journey_token_here\"\n",
       "\n",
       "# Define the payload for creating a journey application\n",
       "payload = {\n",
       "    \"do_await_additional_entities\": False,\n",
       "    \"entities\": [\n",
       "        {\n",
       "            \"branch_name\": \"persons\",\n",
       "            \"data\": {\n",
       "                \"addresses\": [\n",
       "                    {\n",
       "                        \"city\": \"New York\",\n",
       "                        \"country_code\": \"US\",\n",
       "                        \"line_1\": \"41 E. 11th\",\n",
       "                        \"line_2\": \"2nd floor\",\n",
       "                        \"postal_code\": \"10003\",\n",
       "                        \"state\": \"NY\",\n",
       "                        \"type\": \"primary\"\n",
       "                    }\n",
       "                ],\n",
       "                \"birth_date\": \"1990-01-25\",\n",
       "                \"document_ssn\": \"111223333\",\n",
       "                \"email_address\": \"john@alloy.com\",\n",
       "                \"ip_address_v4\": \"42.206.213.70\",\n",
       "                \"meta\": {\n",
       "                    \"user_type\": \"vip\"\n",
       "                },\n",
       "                \"name_first\": \"John\",\n",
       "                \"name_last\": \"Doe\",\n",
       "                \"name_middle\": \"Franklin\",\n",
       "                \"phone_number\": \"8443825569\"\n",
       "            },\n",
       "            \"entity_type\": \"person\",\n",
       "            \"external_entity_id\": \"my_system_entity_id_123\"\n",
       "        }\n",
       "    ]\n",
       "}\n",
       "\n",
       "# Convert the payload to JSON\n",
       "payload_json = json.dumps(payload)\n",
       "\n",
       "# Make the POST request to create the journey application\n",
       "response = requests.post(url.format(journey_token=journey_token), data=payload_json, headers={\"Content-Type\": \"application/json\"})\n",
       "\n",
       "# Check if the request was successful\n",
       "if response.status_code == 201:\n",
       "    print(\"Journey application created successfully!\")\n",
       "else:\n",
       "    print(\"Failed to create journey application. Status code:\", response.status_code)\n",
       "    print(\"Response:\", response.json())\n",
       "```\n",
       "\n",
       "In the code snippet above:\n",
       "- Replace `your_journey_token_here` with the actual journey token you want to create the application for.\n",
       "- Update the `payload` dictionary with the necessary data for creating the journey application.\n",
       "\n",
       "This Python script will send a POST request to create a journey application with the specified data. Make sure to handle any authentication required by the Alloy API based on the security schemes provided in the OpenAPI Specification."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "output = rag_chain.invoke(query)\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5864338-dbc9-4ee7-942f-cf39350ed2c1",
   "metadata": {},
   "source": [
    "### 👎 Better prompting was not helpful, what if we switch out the model for gpt-4 instead of gpt-3.5\n",
    "\n",
    "### 🤔 What is the cost of tokens for gpt-4 with our new RAG architecture"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "cbdde659-7968-41c1-ab29-88c557c884ac",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "gpt-4-turbo: Price of passing in alloy.com.yaml 1 time: $0.12483\n",
      "gpt-4-turbo: Price of passing in alloy.com.yaml 20 times: $2.4966\n",
      "gpt-3.5-turbo: Price of passing in alloy.com.yaml 1 time: $0.0062415\n",
      "gpt-3.5-turbo: Price of passing in alloy.com.yaml 20 times: $0.12483\n"
     ]
    }
   ],
   "source": [
    "import tiktoken\n",
    "\n",
    "# To get the tokeniser corresponding to a specific model in the OpenAI API:\n",
    "enc = tiktoken.get_encoding(\"cl100k_base\")\n",
    "\n",
    "relevant_docs = retriever.invoke(query)\n",
    "\n",
    "tokens = []\n",
    "for doc in relevant_docs:\n",
    "    tokens += enc.encode(doc.page_content)\n",
    "len(tokens)\n",
    "gpt4_price = len(tokens) * 10 / 1_000_000\n",
    "gpt35_price = len(tokens) * 0.5 / 1_000_000\n",
    "print(\"gpt-4-turbo: Price of passing in alloy.com.yaml 1 time: ${}\".format(gpt4_price))\n",
    "print(\"gpt-4-turbo: Price of passing in alloy.com.yaml 20 times: ${}\".format(gpt4_price * 20))\n",
    "print(\"gpt-3.5-turbo: Price of passing in alloy.com.yaml 1 time: ${}\".format(gpt35_price))\n",
    "print(\"gpt-3.5-turbo: Price of passing in alloy.com.yaml 20 times: ${}\".format(gpt35_price * 20))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d2d493f-4868-4117-a5ea-9879670a24f2",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true
   },
   "source": [
    "### RAG vs. Long Context\n",
    "\n",
    "| Model   | RAG     | Long Context |\n",
    "|---------|---------|--------------|\n",
    "| GPT-4   | \\$0.124  | \\$0.5 (4x)    |\n",
    "| GPT-3.5 | \\$0.006  | \\$0.025 (4x)   |\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7b123cbc-f72c-4589-8729-865cfa05e181",
   "metadata": {},
   "source": [
    "### 👎 Still kind of expensive\n",
    "\n",
    "### 🤔 What if we limit context to 2 documents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "9e472810-0765-445e-9119-b16ec97aff55",
   "metadata": {},
   "outputs": [],
   "source": [
    "metadata_field_info = [\n",
    "    AttributeInfo(\n",
    "        name=\"path\",\n",
    "        description=\"The subpath for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"method\",\n",
    "        description=\"The HTTP Method for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"tag\",\n",
    "        description=\"The logical grouping for this API operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"summary\",\n",
    "        description=\"A short description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"description\",\n",
    "        description=\"A more detailed description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "]\n",
    "document_content_description = \"The pruned OpenAPI specification which includes only the relevant information for a particular operation in the OpenAPI specification.\"\n",
    "\n",
    "# Dylan: really stupid, but I had to upgrade langchain to get this to work for some reason\n",
    "retriever = SelfQueryRetriever.from_llm(\n",
    "    chat, vectorstore, document_content_description, metadata_field_info, verbose=True, search_kwargs={\"k\": 2}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "00ac4ecf-038d-442a-b989-6e841ed3e7aa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "gpt-4-turbo: Price of passing in alloy.com.yaml 1 time: $0.07569\n",
      "gpt-4-turbo: Price of passing in alloy.com.yaml 20 times: $1.5137999999999998\n",
      "gpt-3.5-turbo: Price of passing in alloy.com.yaml 1 time: $0.0037845\n",
      "gpt-3.5-turbo: Price of passing in alloy.com.yaml 20 times: $0.07569000000000001\n"
     ]
    }
   ],
   "source": [
    "import tiktoken\n",
    "\n",
    "# To get the tokeniser corresponding to a specific model in the OpenAI API:\n",
    "enc = tiktoken.get_encoding(\"cl100k_base\")\n",
    "\n",
    "relevant_docs = retriever.invoke(query)\n",
    "\n",
    "tokens = []\n",
    "for doc in relevant_docs:\n",
    "    tokens += enc.encode(doc.page_content)\n",
    "len(tokens)\n",
    "gpt4_price = len(tokens) * 10 / 1_000_000\n",
    "gpt35_price = len(tokens) * 0.5 / 1_000_000\n",
    "print(\"gpt-4-turbo: Price of passing in alloy.com.yaml 1 time: ${}\".format(gpt4_price))\n",
    "print(\"gpt-4-turbo: Price of passing in alloy.com.yaml 20 times: ${}\".format(gpt4_price * 20))\n",
    "print(\"gpt-3.5-turbo: Price of passing in alloy.com.yaml 1 time: ${}\".format(gpt35_price))\n",
    "print(\"gpt-3.5-turbo: Price of passing in alloy.com.yaml 20 times: ${}\".format(gpt35_price * 20))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52937716-211a-411e-a3c3-a2a78da5f3cd",
   "metadata": {},
   "source": [
    "### RAG vs. Long Context\n",
    "\n",
    "| Model   | RAG     | Long Context |\n",
    "|---------|---------|--------------|\n",
    "| GPT-4   | \\$0.075  | \\$0.5 (6.66x)    |\n",
    "| GPT-3.5 | \\$0.0038  | \\$0.025 (6.66x)   |\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "203aa2e1-b5a7-49b0-a778-5fe6b6e3568f",
   "metadata": {},
   "source": [
    "### 🤔 Not bad, but does the output still include all the necessary info?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "5ea86544-be33-4c8c-be2a-6628d4c953de",
   "metadata": {
    "vscode": {
     "languageId": "plaintext"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.chains.query_constructor.base import AttributeInfo\n",
    "from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
    "from langchain_community.vectorstores.chroma import Chroma\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "import os\n",
    "\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "\n",
    "query = \"How do I create a journey application in Python?\"\n",
    "\n",
    "chat = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0, model_kwargs={\"seed\": 0})\n",
    "\n",
    "# Reset the collection to remove embeddings from previous runs\n",
    "Chroma().delete_collection()\n",
    "\n",
    "vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "b95c63ba-1bfe-44d6-9840-35297ec0c964",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "metadata_field_info = [\n",
    "    AttributeInfo(\n",
    "        name=\"path\",\n",
    "        description=\"The subpath for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"method\",\n",
    "        description=\"The HTTP Method for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"tag\",\n",
    "        description=\"The logical grouping for this API operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"summary\",\n",
    "        description=\"A short description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"description\",\n",
    "        description=\"A more detailed description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "]\n",
    "document_content_description = \"The pruned OpenAPI specification which includes only the relevant information for a particular operation in the OpenAPI specification.\"\n",
    "\n",
    "# Dylan: really stupid, but I had to upgrade langchain to get this to work for some reason\n",
    "retriever = SelfQueryRetriever.from_llm(\n",
    "    chat, vectorstore, document_content_description, metadata_field_info, verbose=True, search_kwargs={\"k\": 2}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "e19e903f-4363-4f56-beee-c7461aa1060e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "better_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"\"\"You are a world-class solutions engineer and amazing at question-answering tasks. You are also a world-class API\n",
    "            integrations specialist and deeply understand OpenAPI Specification.\n",
    "            \n",
    "            You strictly follow these rules:\n",
    "            - If you don't know the answer, just say that you don't know.\n",
    "            - Use markdown to ensure code blocks and commands are propertly formatted.\n",
    "            - Make sure to always include environment setup instructions and code blocks that are helpful for a developer to copy-paste.\n",
    "            - Always explain inputs and outputs of API requests. Be as detailed as possible.\n",
    "            - When presented with an OpenAPI Specification and asked questions about it, always include necessary steps to\n",
    "            authenticate with the endpoint.\n",
    "            - When presented with multiple authentication options, make sure to guide the customer through both methods\n",
    "            \n",
    "            Answer the user's questions based on the below context:\\n\\n{context}\"\"\",\n",
    "        ),\n",
    "        (\n",
    "            \"user\",\n",
    "            \"{question}\"\n",
    "        )\n",
    "    ]\n",
    ")\n",
    "\n",
    "def format_docs(docs):\n",
    "    return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
    "\n",
    "rag_chain = (\n",
    "    {\"context\": retriever | format_docs, \"question\": RunnablePassthrough()}\n",
    "    | better_prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "da6d6bfc-2c20-4935-b049-1cd4ce2cbad6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey application using the Alloy API in Python, you will need to follow these steps:\n",
       "\n",
       "1. **Authenticate with the Alloy API**:\n",
       "   - The Alloy API uses OAuth2 for authentication. You will need to obtain a bearer token using your workflow token and secret.\n",
       "   - Here is an example of how you can authenticate using OAuth2 in Python:\n",
       "\n",
       "```python\n",
       "import requests\n",
       "\n",
       "url = \"https://demo-qasandbox.alloy.co/oauth/bearer\"\n",
       "payload = {\n",
       "    \"grant_type\": \"client_credentials\",\n",
       "    \"client_id\": \"your_workflow_token\",\n",
       "    \"client_secret\": \"your_workflow_secret\"\n",
       "}\n",
       "response = requests.post(url, data=payload)\n",
       "bearer_token = response.json()[\"access_token\"]\n",
       "```\n",
       "\n",
       "2. **Create a Journey Application**:\n",
       "   - Once you have obtained the bearer token, you can proceed to create a journey application by sending a POST request to the `/journeys/{journey_token}/applications` endpoint.\n",
       "   - You will need to provide the necessary data in the request body, such as the list of entities to be processed in the application.\n",
       "   - Here is an example of how you can create a journey application in Python:\n",
       "\n",
       "```python\n",
       "import requests\n",
       "\n",
       "url = \"https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications\"\n",
       "headers = {\n",
       "    \"Authorization\": f\"Bearer {bearer_token}\",\n",
       "    \"Content-Type\": \"application/json\"\n",
       "}\n",
       "payload = {\n",
       "    \"do_await_additional_entities\": False,\n",
       "    \"entities\": [\n",
       "        {\n",
       "            \"branch_name\": \"persons\",\n",
       "            \"data\": {\n",
       "                \"addresses\": [\n",
       "                    {\n",
       "                        \"city\": \"New York\",\n",
       "                        \"country_code\": \"US\",\n",
       "                        \"line_1\": \"41 E. 11th\",\n",
       "                        \"line_2\": \"2nd floor\",\n",
       "                        \"postal_code\": \"10003\",\n",
       "                        \"state\": \"NY\",\n",
       "                        \"type\": \"primary\"\n",
       "                    }\n",
       "                ],\n",
       "                \"birth_date\": \"1990-01-25\",\n",
       "                \"document_ssn\": \"111223333\",\n",
       "                \"email_address\": \"john@alloy.com\",\n",
       "                \"ip_address_v4\": \"42.206.213.70\",\n",
       "                \"meta\": {\n",
       "                    \"user_type\": \"vip\"\n",
       "                },\n",
       "                \"name_first\": \"John\",\n",
       "                \"name_last\": \"Doe\",\n",
       "                \"name_middle\": \"Franklin\",\n",
       "                \"phone_number\": \"8443825569\"\n",
       "            },\n",
       "            \"entity_type\": \"person\",\n",
       "            \"external_entity_id\": \"my_system_entity_id_123\"\n",
       "        }\n",
       "    ]\n",
       "}\n",
       "\n",
       "response = requests.post(url, headers=headers, json=payload)\n",
       "print(response.json())\n",
       "```\n",
       "\n",
       "3. **Handle the Response**:\n",
       "   - The response will contain information about the created journey application, such as the application token and any additional details.\n",
       "\n",
       "This is a basic example of how you can create a journey application using the Alloy API in Python. Make sure to replace placeholders like `{journey_token}`, `your_workflow_token`, and `your_workflow_secret` with your actual values."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "output = rag_chain.invoke(query)\n",
    "\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d48ea7c-0ac7-4742-bf97-a9ff9448a703",
   "metadata": {},
   "source": [
    "### 👎 Guide for security authorization was not helpful\n",
    "\n",
    "### 🤔 Does it produce significantl better results with gpt-4?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "25347350-ba1a-47b9-845c-6dda321e59fc",
   "metadata": {
    "vscode": {
     "languageId": "plaintext"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.chains.query_constructor.base import AttributeInfo\n",
    "from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
    "from langchain_community.vectorstores.chroma import Chroma\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "import os\n",
    "\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "\n",
    "query = \"How do I create a journey application in Python?\"\n",
    "\n",
    "chat = ChatOpenAI(model=\"gpt-4-turbo\", temperature=0, model_kwargs={\"seed\": 0})\n",
    "\n",
    "# Reset the collection to remove embeddings from previous runs\n",
    "Chroma().delete_collection()\n",
    "\n",
    "vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "22a0d8ea-fb03-430b-9c5a-1da62fd4a63a",
   "metadata": {},
   "outputs": [],
   "source": [
    "metadata_field_info = [\n",
    "    AttributeInfo(\n",
    "        name=\"path\",\n",
    "        description=\"The subpath for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"method\",\n",
    "        description=\"The HTTP Method for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"tag\",\n",
    "        description=\"The logical grouping for this API operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"summary\",\n",
    "        description=\"A short description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"description\",\n",
    "        description=\"A more detailed description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "]\n",
    "document_content_description = \"The pruned OpenAPI specification which includes only the relevant information for a particular operation in the OpenAPI specification.\"\n",
    "\n",
    "# Dylan: really stupid, but I had to upgrade langchain to get this to work for some reason\n",
    "retriever = SelfQueryRetriever.from_llm(\n",
    "    chat, vectorstore, document_content_description, metadata_field_info, verbose=True, search_kwargs={\"k\": 2}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "70660c05-6b8c-4f9a-8c6f-4140f69af9c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "better_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"\"\"You are a world-class solutions engineer and amazing at question-answering tasks. You are also a world-class API\n",
    "            integrations specialist and deeply understand OpenAPI Specification.\n",
    "            \n",
    "            You strictly follow these rules:\n",
    "            - If you don't know the answer, just say that you don't know.\n",
    "            - Use markdown to ensure code blocks and commands are propertly formatted.\n",
    "            - Make sure to always include environment setup instructions and code blocks that are helpful for a developer to copy-paste.\n",
    "            - Always explain inputs and outputs of API requests. Be as detailed as possible.\n",
    "            - When presented with an OpenAPI Specification and asked questions about it, always include necessary steps to\n",
    "            authenticate with the endpoint.\n",
    "            - When presented with multiple authentication options, make sure to guide the customer through both methods\n",
    "            \n",
    "            Answer the user's questions based on the below context:\\n\\n{context}\"\"\",\n",
    "        ),\n",
    "        (\n",
    "            \"user\",\n",
    "            \"{question}\"\n",
    "        )\n",
    "    ]\n",
    ")\n",
    "\n",
    "def format_docs(docs):\n",
    "    return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
    "\n",
    "rag_chain = (\n",
    "    {\"context\": retriever | format_docs, \"question\": RunnablePassthrough()}\n",
    "    | better_prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "fa849104-7906-4ac3-8059-e4f509367b19",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey application using the Alloy API in Python, you'll need to follow these steps. This involves setting up your environment, authenticating with the API, and making a POST request to the appropriate endpoint.\n",
       "\n",
       "### Environment Setup\n",
       "\n",
       "First, ensure you have Python installed on your system. You can download Python from [python.org](https://www.python.org/downloads/). You will also need to install the `requests` library, which is used for making HTTP requests. You can install this library using pip:\n",
       "\n",
       "```bash\n",
       "pip install requests\n",
       "```\n",
       "\n",
       "### Authentication\n",
       "\n",
       "The Alloy API provides two methods for authentication: Basic Authentication and OAuth2. Here's how you can authenticate using both methods:\n",
       "\n",
       "#### 1. Basic Authentication\n",
       "\n",
       "For Basic Authentication, you need a workflow token and secret. These should be encoded in base64 and used as the Authorization header.\n",
       "\n",
       "```python\n",
       "import base64\n",
       "\n",
       "def get_basic_auth_header(token, secret):\n",
       "    token_secret = f\"{token}:{secret}\".encode('utf-8')\n",
       "    b64_encoded = base64.b64encode(token_secret).decode('utf-8')\n",
       "    return {\"Authorization\": f\"Basic {b64_encoded}\"}\n",
       "```\n",
       "\n",
       "#### 2. OAuth2 Authentication\n",
       "\n",
       "For OAuth2, you need to obtain a bearer token using the client credentials flow.\n",
       "\n",
       "```python\n",
       "def get_oauth2_token(client_id, client_secret, token_url):\n",
       "    response = requests.post(\n",
       "        token_url,\n",
       "        auth=(client_id, client_secret)\n",
       "    )\n",
       "    return response.json()['access_token']\n",
       "\n",
       "# Example usage\n",
       "token_url = 'https://demo-qasandbox.alloy.co/v1/oauth/bearer'\n",
       "access_token = get_oauth2_token('your_client_id', 'your_client_secret', token_url)\n",
       "auth_header = {\"Authorization\": f\"Bearer {access_token}\"}\n",
       "```\n",
       "\n",
       "### Making the POST Request\n",
       "\n",
       "Once authenticated, you can create a journey application by making a POST request to the `/journeys/{journey_token}/applications` endpoint.\n",
       "\n",
       "```python\n",
       "import requests\n",
       "import json\n",
       "\n",
       "def create_journey_application(journey_token, entities, auth_header):\n",
       "    url = f\"https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications\"\n",
       "    payload = {\n",
       "        \"entities\": entities,\n",
       "        \"do_await_additional_entities\": False\n",
       "    }\n",
       "    headers = {\n",
       "        **auth_header,\n",
       "        \"Content-Type\": \"application/json\"\n",
       "    }\n",
       "    response = requests.post(url, headers=headers, data=json.dumps(payload))\n",
       "    return response.json()\n",
       "\n",
       "# Example usage\n",
       "journey_token = \"your_journey_token\"\n",
       "entities = [\n",
       "    {\n",
       "        \"branch_name\": \"persons\",\n",
       "        \"data\": {\n",
       "            \"name_first\": \"John\",\n",
       "            \"name_last\": \"Doe\",\n",
       "            \"birth_date\": \"1990-01-25\",\n",
       "            \"document_ssn\": \"111223333\",\n",
       "            \"email_address\": \"john@alloy.com\",\n",
       "            \"phone_number\": \"8443825569\",\n",
       "            \"addresses\": [\n",
       "                {\n",
       "                    \"line_1\": \"41 E. 11th\",\n",
       "                    \"line_2\": \"2nd floor\",\n",
       "                    \"city\": \"New York\",\n",
       "                    \"state\": \"NY\",\n",
       "                    \"postal_code\": \"10003\",\n",
       "                    \"country_code\": \"US\",\n",
       "                    \"type\": \"primary\"\n",
       "                }\n",
       "            ]\n",
       "        },\n",
       "        \"entity_type\": \"person\",\n",
       "        \"external_entity_id\": \"my_system_entity_id_123\"\n",
       "    }\n",
       "]\n",
       "\n",
       "# Choose the authentication method\n",
       "auth_header = get_basic_auth_header('your_token', 'your_secret')\n",
       "# Or use OAuth2\n",
       "# auth_header = {\"Authorization\": f\"Bearer {access_token}\"}\n",
       "\n",
       "response = create_journey_application(journey_token, entities, auth_header)\n",
       "print(response)\n",
       "```\n",
       "\n",
       "This script sets up the necessary headers, constructs the JSON payload for the request, and handles the API response. Adjust the `entities` list according to the specific requirements of your application."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "output = rag_chain.invoke(query)\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "147f7472-0c67-4ddb-b275-0f81125ea312",
   "metadata": {},
   "source": [
    "### 👍 Pretty good\n",
    "\n",
    "Includes both options for authentication and copy-pastable code examples\n",
    "\n",
    "### 🤔 What about making it so security credentials are pulled through environment variables\n",
    "\n",
    "Lets try editing the system prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "cb9952a2-b56f-43d3-bc15-56ba7c7f7f0c",
   "metadata": {
    "vscode": {
     "languageId": "plaintext"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.chains.query_constructor.base import AttributeInfo\n",
    "from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
    "from langchain_community.vectorstores.chroma import Chroma\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "import os\n",
    "\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "\n",
    "query = \"How do I create a journey application in Python?\"\n",
    "\n",
    "chat = ChatOpenAI(model=\"gpt-4-turbo\", temperature=0, model_kwargs={\"seed\": 0})\n",
    "\n",
    "# Reset the collection to remove embeddings from previous runs\n",
    "Chroma().delete_collection()\n",
    "\n",
    "vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "db426e4d-6dde-4198-b2b5-7ffe4aa6e6a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "metadata_field_info = [\n",
    "    AttributeInfo(\n",
    "        name=\"path\",\n",
    "        description=\"The subpath for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"method\",\n",
    "        description=\"The HTTP Method for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"tag\",\n",
    "        description=\"The logical grouping for this API operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"summary\",\n",
    "        description=\"A short description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"description\",\n",
    "        description=\"A more detailed description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "]\n",
    "document_content_description = \"The pruned OpenAPI specification which includes only the relevant information for a particular operation in the OpenAPI specification.\"\n",
    "\n",
    "# Dylan: really stupid, but I had to upgrade langchain to get this to work for some reason\n",
    "retriever = SelfQueryRetriever.from_llm(\n",
    "    chat, vectorstore, document_content_description, metadata_field_info, verbose=True, search_kwargs={\"k\": 2}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "4a02ef4c-9017-404d-99bc-72933d7c4a53",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "better_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"\"\"You are a world-class solutions engineer and amazing at question-answering tasks. You are also a world-class API\n",
    "            integrations specialist and deeply understand OpenAPI Specification. You also deeply unde\n",
    "            rstand computer security which\n",
    "            allows you to produce secure code examples and guidance.\n",
    "            \n",
    "            You strictly follow these rules:\n",
    "            - If you don't know the answer, just say that you don't know.\n",
    "            - Use markdown to ensure code blocks and commands are propertly formatted.\n",
    "            - Make sure to always include environment setup instructions and code blocks that are helpful for a developer to copy-paste.\n",
    "            - Always explain inputs and outputs of API requests. Be as detailed as possible.\n",
    "            - When presented with an OpenAPI Specification and asked questions about it, always include necessary steps to\n",
    "            authenticate with the endpoint.\n",
    "            - When presented with multiple authentication options, make sure to guide the customer through both methods\n",
    "            - Always name variables for security credentials based on standard protocols, API name, or descriptions\n",
    "            - For example if the following security scheme is:\n",
    "  \"securitySchemes:\n",
    "    basic:\n",
    "      type: http\n",
    "      description: HTTP basic authorization using a workflow token and secret\n",
    "      scheme: Basic\"\n",
    "\n",
    "or\n",
    "\n",
    "    \"oauth2:\n",
    "      type: oauth2\n",
    "      x-default: viSRrSuUJEid8u0l3dyRTj5ATsWpHX9ShD51TH3j\n",
    "      description: Oauth2 using a workflow token and secret to generate a bearer token\n",
    "      flows:\n",
    "        clientCredentials:\n",
    "          tokenUrl: /oauth/bearer\"\n",
    "      \n",
    "              Then you would name the variables in code as \"ALLOY_WORKFLOW_TOKEN\" and \"ALLOY_WORKFLOW_SECRET\".\n",
    "            - When referencing security credentials, always pull values from environment variables.\n",
    "            \n",
    "            Answer the user's questions based on the below context:\\n\\n{context}\"\"\",\n",
    "        ),\n",
    "        (\n",
    "            \"user\",\n",
    "            \"{question}\"\n",
    "        )\n",
    "    ]\n",
    ")\n",
    "\n",
    "def format_docs(docs):\n",
    "    return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
    "\n",
    "rag_chain = (\n",
    "    {\"context\": retriever | format_docs, \"question\": RunnablePassthrough()}\n",
    "    | better_prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "cd06b695-df13-43be-9585-a0634953a5b0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey application using the Alloy API in Python, you'll need to authenticate and send a POST request to the appropriate endpoint. Below, I'll guide you through setting up your environment, authenticating using both Basic and OAuth2 methods, and making the API request.\n",
       "\n",
       "### Environment Setup\n",
       "\n",
       "First, ensure you have Python and `requests` library installed. You can install the `requests` library using pip if you haven't already:\n",
       "\n",
       "```bash\n",
       "pip install requests\n",
       "```\n",
       "\n",
       "### Authentication\n",
       "\n",
       "The Alloy API provides two methods for authentication: Basic and OAuth2. I'll provide examples for both.\n",
       "\n",
       "#### 1. Basic Authentication\n",
       "\n",
       "For Basic Authentication, you need your workflow token and secret. These should be stored securely and not hard-coded in your scripts. Use environment variables to store these credentials.\n",
       "\n",
       "```python\n",
       "import os\n",
       "import requests\n",
       "from requests.auth import HTTPBasicAuth\n",
       "\n",
       "# Environment variables for security credentials\n",
       "ALLOY_WORKFLOW_TOKEN = os.getenv('ALLOY_WORKFLOW_TOKEN')\n",
       "ALLOY_WORKFLOW_SECRET = os.getenv('ALLOY_WORKFLOW_SECRET')\n",
       "\n",
       "# API endpoint\n",
       "url = \"https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications\"\n",
       "\n",
       "# Replace {journey_token} with your actual journey token\n",
       "url = url.format(journey_token=\"your_journey_token_here\")\n",
       "\n",
       "# Request body\n",
       "payload = {\n",
       "    \"do_await_additional_entities\": False,\n",
       "    \"entities\": [\n",
       "        {\n",
       "            \"branch_name\": \"persons\",\n",
       "            \"data\": {\n",
       "                \"addresses\": [\n",
       "                    {\n",
       "                        \"city\": \"New York\",\n",
       "                        \"country_code\": \"US\",\n",
       "                        \"line_1\": \"41 E. 11th\",\n",
       "                        \"line_2\": \"2nd floor\",\n",
       "                        \"postal_code\": \"10003\",\n",
       "                        \"state\": \"NY\",\n",
       "                        \"type\": \"primary\"\n",
       "                    }\n",
       "                ],\n",
       "                \"birth_date\": \"1990-01-25\",\n",
       "                \"document_ssn\": 111223333,\n",
       "                \"email_address\": \"john@alloy.com\",\n",
       "                \"ip_address_v4\": \"42.206.213.70\",\n",
       "                \"meta\": {\n",
       "                    \"user_type\": \"vip\"\n",
       "                },\n",
       "                \"name_first\": \"John\",\n",
       "                \"name_last\": \"Doe\",\n",
       "                \"name_middle\": \"Franklin\",\n",
       "                \"phone_number\": 8443825569\n",
       "            },\n",
       "            \"entity_type\": \"person\",\n",
       "            \"external_entity_id\": \"my_system_entity_id_123\"\n",
       "        }\n",
       "    ]\n",
       "}\n",
       "\n",
       "# Headers\n",
       "headers = {\n",
       "    'Content-Type': 'application/json'\n",
       "}\n",
       "\n",
       "# Make the POST request\n",
       "response = requests.post(url, json=payload, auth=HTTPBasicAuth(ALLOY_WORKFLOW_TOKEN, ALLOY_WORKFLOW_SECRET), headers=headers)\n",
       "\n",
       "# Print the response\n",
       "print(response.json())\n",
       "```\n",
       "\n",
       "#### 2. OAuth2 Authentication\n",
       "\n",
       "For OAuth2, you'll first need to obtain a bearer token using the client credentials flow.\n",
       "\n",
       "```python\n",
       "# Token endpoint\n",
       "token_url = \"https://demo-qasandbox.alloy.co/v1/oauth/bearer\"\n",
       "\n",
       "# Obtain the bearer token\n",
       "token_response = requests.post(token_url, auth=HTTPBasicAuth(ALLOY_WORKFLOW_TOKEN, ALLOY_WORKFLOW_SECRET))\n",
       "access_token = token_response.json().get('access_token')\n",
       "\n",
       "# Headers with the bearer token\n",
       "headers = {\n",
       "    'Authorization': f'Bearer {access_token}',\n",
       "    'Content-Type': 'application/json'\n",
       "}\n",
       "\n",
       "# Make the POST request\n",
       "response = requests.post(url, json=payload, headers=headers)\n",
       "\n",
       "# Print the response\n",
       "print(response.json())\n",
       "```\n",
       "\n",
       "### Inputs and Outputs\n",
       "\n",
       "- **Inputs**: The request body includes details about the entities involved in the journey application, such as personal information, addresses, and other metadata.\n",
       "- **Outputs**: The response will include details about the created journey application, such as tokens, links to related resources, and status information.\n",
       "\n",
       "Make sure to replace placeholders like `your_journey_token_here` with actual values relevant to your use case. Always handle sensitive data such as tokens and personal information securely."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "output = rag_chain.invoke(query)\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60704476-535c-4dd8-a6b3-885134b2971e",
   "metadata": {},
   "source": [
    "### 👍 Excellent\n",
    "\n",
    "Looks like we should be using RAG (to reduce cost) + GPT-4 (for quality).\n",
    "\n",
    "### 🤔 What about in Java?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "6fdd4825-9b1a-4a24-a73e-0668daec578e",
   "metadata": {
    "vscode": {
     "languageId": "plaintext"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.chains.query_constructor.base import AttributeInfo\n",
    "from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
    "from langchain_community.vectorstores.chroma import Chroma\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "import os\n",
    "\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "\n",
    "query = \"How do I create a journey application in Java?\"\n",
    "\n",
    "chat = ChatOpenAI(model=\"gpt-4-turbo\", temperature=0, model_kwargs={\"seed\": 0})\n",
    "\n",
    "# Reset the collection to remove embeddings from previous runs\n",
    "Chroma().delete_collection()\n",
    "\n",
    "vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "f98fbb14-ffca-4f54-b4c2-f3fa724e58a6",
   "metadata": {},
   "outputs": [],
   "source": [
    "metadata_field_info = [\n",
    "    AttributeInfo(\n",
    "        name=\"path\",\n",
    "        description=\"The subpath for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"method\",\n",
    "        description=\"The HTTP Method for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"tag\",\n",
    "        description=\"The logical grouping for this API operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"summary\",\n",
    "        description=\"A short description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"description\",\n",
    "        description=\"A more detailed description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "]\n",
    "document_content_description = \"The pruned OpenAPI specification which includes only the relevant information for a particular operation in the OpenAPI specification.\"\n",
    "\n",
    "# Dylan: really stupid, but I had to upgrade langchain to get this to work for some reason\n",
    "retriever = SelfQueryRetriever.from_llm(\n",
    "    chat, vectorstore, document_content_description, metadata_field_info, verbose=True, search_kwargs={\"k\": 2}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "f2bb60e8-34bf-4e67-b4c6-83744e298564",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "better_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"\"\"You are a world-class solutions engineer and amazing at question-answering tasks. You are also a world-class API\n",
    "            integrations specialist and deeply understand OpenAPI Specification. You also deeply unde\n",
    "            rstand computer security which\n",
    "            allows you to produce secure code examples and guidance.\n",
    "            \n",
    "            You strictly follow these rules:\n",
    "            - If you don't know the answer, just say that you don't know.\n",
    "            - Use markdown to ensure code blocks and commands are propertly formatted.\n",
    "            - Make sure to always include environment setup instructions and code blocks that are helpful for a developer to copy-paste.\n",
    "            - Always explain inputs and outputs of API requests. Be as detailed as possible.\n",
    "            - When presented with an OpenAPI Specification and asked questions about it, always include necessary steps to\n",
    "            authenticate with the endpoint.\n",
    "            - When presented with multiple authentication options, make sure to guide the customer through both methods of authentication in code\n",
    "            - Always name variables for security credentials based on standard protocols, API name, or descriptions\n",
    "            - For example if the following security scheme is:\n",
    "  \"securitySchemes:\n",
    "    basic:\n",
    "      type: http\n",
    "      description: HTTP basic authorization using a workflow token and secret\n",
    "      scheme: Basic\"\n",
    "\n",
    "or\n",
    "\n",
    "    \"oauth2:\n",
    "      type: oauth2\n",
    "      x-default: viSRrSuUJEid8u0l3dyRTj5ATsWpHX9ShD51TH3j\n",
    "      description: Oauth2 using a workflow token and secret to generate a bearer token\n",
    "      flows:\n",
    "        clientCredentials:\n",
    "          tokenUrl: /oauth/bearer\"\n",
    "      \n",
    "              Then you would name the variables in code as \"ALLOY_WORKFLOW_TOKEN\" and \"ALLOY_WORKFLOW_SECRET\".\n",
    "            - When referencing security credentials, always pull values from environment variables.\n",
    "            \n",
    "            Answer the user's questions based on the below context:\\n\\n{context}\"\"\",\n",
    "        ),\n",
    "        (\n",
    "            \"user\",\n",
    "            \"{question}\"\n",
    "        )\n",
    "    ]\n",
    ")\n",
    "\n",
    "def format_docs(docs):\n",
    "    return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
    "\n",
    "rag_chain = (\n",
    "    {\"context\": retriever | format_docs, \"question\": RunnablePassthrough()}\n",
    "    | better_prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "0de50f6e-c651-4c6c-bf61-3e9bb4c76ba3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey application using the Alloy API in Java, you'll need to set up your environment and authenticate with the API. You can choose between Basic Authentication and OAuth2 for authentication. Below, I'll guide you through both methods.\n",
       "\n",
       "### Prerequisites\n",
       "1. Java Development Kit (JDK) - Ensure you have Java installed on your system. You can download it from [Oracle's JDK Download Page](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html).\n",
       "2. An IDE or a simple text editor for writing your Java code.\n",
       "3. A library for making HTTP requests. In this example, I'll use `OkHttp` for making requests. You can add it to your project using Maven or Gradle.\n",
       "\n",
       "### Adding Dependencies\n",
       "If you are using Maven, add the following dependencies to your `pom.xml`:\n",
       "\n",
       "```xml\n",
       "<dependencies>\n",
       "    <dependency>\n",
       "        <groupId>com.squareup.okhttp3</groupId>\n",
       "        <artifactId>okhttp</artifactId>\n",
       "        <version>4.9.0</version>\n",
       "    </dependency>\n",
       "</dependencies>\n",
       "```\n",
       "\n",
       "For Gradle, add this to your `build.gradle`:\n",
       "\n",
       "```gradle\n",
       "dependencies {\n",
       "    implementation 'com.squareup.okhttp3:okhttp:4.9.0'\n",
       "}\n",
       "```\n",
       "\n",
       "### Environment Setup\n",
       "Set up environment variables for your credentials. This is a secure way to handle sensitive data like API keys and tokens.\n",
       "\n",
       "```bash\n",
       "export ALLOY_WORKFLOW_TOKEN=\"your_workflow_token\"\n",
       "export ALLOY_WORKFLOW_SECRET=\"your_workflow_secret\"\n",
       "```\n",
       "\n",
       "### Code Example\n",
       "Here’s how you can write the Java code to create a journey application. I'll provide examples for both Basic Authentication and OAuth2.\n",
       "\n",
       "#### Using Basic Authentication\n",
       "\n",
       "```java\n",
       "import okhttp3.Credentials;\n",
       "import okhttp3.MediaType;\n",
       "import okhttp3.OkHttpClient;\n",
       "import okhttp3.Request;\n",
       "import okhttp3.RequestBody;\n",
       "import okhttp3.Response;\n",
       "\n",
       "public class AlloyApiExample {\n",
       "    public static void main(String[] args) {\n",
       "        try {\n",
       "            OkHttpClient client = new OkHttpClient();\n",
       "\n",
       "            String credentials = Credentials.basic(System.getenv(\"ALLOY_WORKFLOW_TOKEN\"), System.getenv(\"ALLOY_WORKFLOW_SECRET\"));\n",
       "            MediaType mediaType = MediaType.parse(\"application/json\");\n",
       "            RequestBody body = RequestBody.create(mediaType, \"{\\n    \\\"entities\\\": [\\n        {\\n            \\\"branch_name\\\": \\\"persons\\\",\\n            \\\"data\\\": {\\n                \\\"name_first\\\": \\\"John\\\",\\n                \\\"name_last\\\": \\\"Doe\\\",\\n                \\\"birth_date\\\": \\\"1990-01-25\\\",\\n                \\\"email_address\\\": \\\"john@alloy.com\\\"\\n            },\\n            \\\"entity_type\\\": \\\"person\\\"\\n        }\\n    ]\\n}\");\n",
       "            Request request = new Request.Builder()\n",
       "                .url(\"https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications\")\n",
       "                .post(body)\n",
       "                .addHeader(\"Authorization\", credentials)\n",
       "                .addHeader(\"Content-Type\", \"application/json\")\n",
       "                .build();\n",
       "\n",
       "            Response response = client.newCall(request).execute();\n",
       "            System.out.println(response.body().string());\n",
       "        } catch (Exception e) {\n",
       "            e.printStackTrace();\n",
       "        }\n",
       "    }\n",
       "}\n",
       "```\n",
       "\n",
       "#### Using OAuth2\n",
       "\n",
       "First, you need to obtain a bearer token using the client credentials flow:\n",
       "\n",
       "```java\n",
       "import okhttp3.*;\n",
       "\n",
       "public class OAuthTokenFetcher {\n",
       "    public static String fetchAccessToken() throws Exception {\n",
       "        OkHttpClient client = new OkHttpClient();\n",
       "        String credentials = Credentials.basic(System.getenv(\"ALLOY_WORKFLOW_TOKEN\"), System.getenv(\"ALLOY_WORKFLOW_SECRET\"));\n",
       "        RequestBody body = RequestBody.create(MediaType.parse(\"application/x-www-form-urlencoded\"), \"grant_type=client_credentials\");\n",
       "        Request request = new Request.Builder()\n",
       "            .url(\"https://demo-qasandbox.alloy.co/oauth/bearer\")\n",
       "            .post(body)\n",
       "            .addHeader(\"Authorization\", credentials)\n",
       "            .build();\n",
       "\n",
       "        Response response = client.newCall(request).execute();\n",
       "        // Extract the access token from the response body\n",
       "        // This is a simplified example, you should parse the JSON response\n",
       "        return \"extracted_access_token\";\n",
       "    }\n",
       "}\n",
       "```\n",
       "\n",
       "Then use the token to make the API request:\n",
       "\n",
       "```java\n",
       "public class AlloyApiOAuthExample {\n",
       "    public static void main(String[] args) {\n",
       "        try {\n",
       "            String accessToken = OAuthTokenFetcher.fetchAccessToken();\n",
       "            OkHttpClient client = new OkHttpClient();\n",
       "\n",
       "            MediaType mediaType = MediaType.parse(\"application/json\");\n",
       "            RequestBody body = RequestBody.create(mediaType, \"{\\n    \\\"entities\\\": [\\n        {\\n            \\\"branch_name\\\": \\\"persons\\\",\\n            \\\"data\\\": {\\n                \\\"name_first\\\": \\\"John\\\",\\n                \\\"name_last\\\": \\\"Doe\\\",\\n                \\\"birth_date\\\": \\\"1990-01-25\\\",\\n                \\\"email_address\\\": \\\"john@alloy.com\\\"\\n            },\\n            \\\"entity_type\\\": \\\"person\\\"\\n        }\\n    ]\\n}\");\n",
       "            Request request = new Request.Builder()\n",
       "                .url(\"https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications\")\n",
       "                .post(body)\n",
       "                .addHeader(\"Authorization\", \"Bearer \" + accessToken)\n",
       "                .addHeader(\"Content-Type\", \"application/json\")\n",
       "                .build();\n",
       "\n",
       "            Response response = client.newCall(request).execute();\n",
       "            System.out.println(response.body().string());\n",
       "        } catch (Exception e) {\n",
       "            e.printStackTrace();\n",
       "        }\n",
       "    }\n",
       "}\n",
       "```\n",
       "\n",
       "### Explanation\n",
       "- Replace `{journey_token}` with the actual journey token you want to use.\n",
       "- The JSON body in the `RequestBody.create` method should be modified according to the specific requirements of your journey application.\n",
       "\n",
       "This setup should help you successfully create a journey application using the Alloy API in Java."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "output = rag_chain.invoke(query)\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "d191f8a3-da8e-4333-8126-35b8f9bad2a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "query = \"How do I create a journey application in TypeScript?\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "565e2a40-2965-4aa5-977e-0efc92e07a03",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a journey application using the Alloy API in TypeScript, you'll need to follow these steps. This involves setting up your environment, handling authentication, and making the API request. Below, I'll guide you through both Basic and OAuth2 authentication methods as specified in the API documentation.\n",
       "\n",
       "### Environment Setup\n",
       "\n",
       "1. **Install Node.js**: Ensure Node.js is installed in your environment. You can download it from [nodejs.org](https://nodejs.org/).\n",
       "\n",
       "2. **Setup TypeScript**: Install TypeScript globally using npm if you haven't already:\n",
       "   ```bash\n",
       "   npm install -g typescript\n",
       "   ```\n",
       "\n",
       "3. **Create a new project**:\n",
       "   ```bash\n",
       "   mkdir alloy-journey-application\n",
       "   cd alloy-journey-application\n",
       "   npm init -y\n",
       "   tsc --init\n",
       "   ```\n",
       "\n",
       "4. **Install required packages**:\n",
       "   - `axios` for making HTTP requests.\n",
       "   - `dotenv` for managing environment variables.\n",
       "\n",
       "   ```bash\n",
       "   npm install axios dotenv\n",
       "   npm install @types/axios @types/node --save-dev\n",
       "   ```\n",
       "\n",
       "5. **Setup your environment variables**:\n",
       "   Create a `.env` file in your project root and add the following (replace placeholders with actual values):\n",
       "   ```plaintext\n",
       "   ALLOY_WORKFLOW_TOKEN=your_workflow_token\n",
       "   ALLOY_WORKFLOW_SECRET=your_workflow_secret\n",
       "   ```\n",
       "\n",
       "### TypeScript Code Example\n",
       "\n",
       "Create a file named `createJourneyApplication.ts` and add the following TypeScript code. This example includes both Basic and OAuth2 authentication methods.\n",
       "\n",
       "```typescript\n",
       "import axios from 'axios';\n",
       "import * as dotenv from 'dotenv';\n",
       "\n",
       "dotenv.config();\n",
       "\n",
       "const apiUrl = 'https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications';\n",
       "const journeyToken = 'your_journey_token'; // Replace with your actual journey token\n",
       "\n",
       "// Replace placeholders in apiUrl\n",
       "const endpoint = apiUrl.replace('{journey_token}', journeyToken);\n",
       "\n",
       "// Data to be sent in the request body\n",
       "const requestData = {\n",
       "  do_await_additional_entities: false,\n",
       "  entities: [\n",
       "    {\n",
       "      branch_name: 'persons',\n",
       "      data: {\n",
       "        addresses: [\n",
       "          {\n",
       "            city: \"New York\",\n",
       "            country_code: \"US\",\n",
       "            line_1: \"41 E. 11th\",\n",
       "            line_2: \"2nd floor\",\n",
       "            postal_code: \"10003\",\n",
       "            state: \"NY\",\n",
       "            type: \"primary\"\n",
       "          }\n",
       "        ],\n",
       "        birth_date: \"1990-01-25\",\n",
       "        document_ssn: 111223333,\n",
       "        email_address: \"john@alloy.com\",\n",
       "        ip_address_v4: \"42.206.213.70\",\n",
       "        meta: {\n",
       "          user_type: \"vip\"\n",
       "        },\n",
       "        name_first: \"John\",\n",
       "        name_last: \"Doe\",\n",
       "        name_middle: \"Franklin\",\n",
       "        phone_number: 8443825569\n",
       "      },\n",
       "      entity_type: \"person\",\n",
       "      external_entity_id: \"my_system_entity_id_123\"\n",
       "    }\n",
       "  ]\n",
       "};\n",
       "\n",
       "// Function to perform Basic Authentication\n",
       "async function createJourneyApplicationBasicAuth() {\n",
       "  const auth = {\n",
       "    username: process.env.ALLOY_WORKFLOW_TOKEN!,\n",
       "    password: process.env.ALLOY_WORKFLOW_SECRET!\n",
       "  };\n",
       "\n",
       "  try {\n",
       "    const response = await axios.post(endpoint, requestData, { auth });\n",
       "    console.log('Response:', response.data);\n",
       "  } catch (error) {\n",
       "    console.error('Error:', error.response?.data || error.message);\n",
       "  }\n",
       "}\n",
       "\n",
       "// Function to perform OAuth2 Authentication\n",
       "async function createJourneyApplicationOAuth2() {\n",
       "  const tokenResponse = await axios.post('https://demo-qasandbox.alloy.co/oauth/bearer', {}, {\n",
       "    auth: {\n",
       "      username: process.env.ALLOY_WORKFLOW_TOKEN!,\n",
       "      password: process.env.ALLOY_WORKFLOW_SECRET!\n",
       "    }\n",
       "  });\n",
       "\n",
       "  const accessToken = tokenResponse.data.access_token;\n",
       "\n",
       "  try {\n",
       "    const response = await axios.post(endpoint, requestData, {\n",
       "      headers: { Authorization: `Bearer ${accessToken}` }\n",
       "    });\n",
       "    console.log('Response:', response.data);\n",
       "  } catch (error) {\n",
       "    console.error('Error:', error.response?.data || error.message);\n",
       "  }\n",
       "}\n",
       "\n",
       "// Uncomment the function you want to use:\n",
       "// createJourneyApplicationBasicAuth();\n",
       "// createJourneyApplicationOAuth2();\n",
       "```\n",
       "\n",
       "### Running the Code\n",
       "\n",
       "Compile and run your TypeScript file:\n",
       "```bash\n",
       "tsc createJourneyApplication.ts\n",
       "node createJourneyApplication.js\n",
       "```\n",
       "\n",
       "This script will send a POST request to create a journey application with the specified data. Make sure to handle the response and errors appropriately based on your application's needs."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "output = rag_chain.invoke(query)\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6eebc75d-9b00-45d4-920a-9f94b52c9220",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "### 2️⃣ Add documentation and custom configuration to input\n",
    "\n",
    "```mermaid\n",
    "graph LR\n",
    "    alloy.com.yaml --> Context\n",
    "    HWD[Hand-written Documentation] --> Context\n",
    "    JSON[JSON Payload] --> Context\n",
    "    Context --> Chat\n",
    "    Query[How do I create a journey in Python?] --> Chat\n",
    "    Chat --> Guide\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "664772c3-b9c5-411c-8a43-19fd29fb6b8d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "72\n"
     ]
    }
   ],
   "source": [
    "import yaml\n",
    "import jsonref\n",
    "from jsonref import replace_refs\n",
    "from langchain_core.documents.base import Document\n",
    "from copy import deepcopy\n",
    "from pprint import pprint\n",
    "\n",
    "with open(\"alloy.com.yaml\") as f:\n",
    "    spec = f.read()\n",
    "\n",
    "def chunk_openapi_by_operation(openapi: str):\n",
    "    parsed = yaml.safe_load(openapi)\n",
    "\n",
    "    operations: (str, str) = []\n",
    "    # 1) list all operations by (path, HTTP method)\n",
    "    for path, methods in parsed['paths'].items():\n",
    "        for method in methods.keys():\n",
    "            # if method is not an HTTP method then skip\n",
    "            if method.lower() not in ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace']:\n",
    "                continue\n",
    "            operations.append((path, method))\n",
    "\n",
    "    # 2) create a chunk for every operation\n",
    "\n",
    "    # 2.a) Dereference entire OpenAPI Spec\n",
    "    dereferenced = replace_refs(parsed, lazy_load=False)\n",
    "\n",
    "    chunks = []\n",
    "    for operation in operations:\n",
    "        path = operation[0]\n",
    "        method = operation[1]\n",
    "        chunk = deepcopy(dereferenced)\n",
    "        if 'tags' in chunk['paths'][operation[0]][operation[1]]:\n",
    "            tags = chunk['paths'][operation[0]][operation[1]]['tags']\n",
    "\n",
    "        # first tag if possible\n",
    "        if tags:\n",
    "            tag_name = tags[0]\n",
    "\n",
    "        # delete all tags on OAS except tag for this operation\n",
    "        while len(chunk['tags']) > 1:\n",
    "            for i in range(len(chunk['tags']) - 1, -1, -1):\n",
    "                if chunk['tags'][i]['name'] != tag_name:\n",
    "                    chunk['tags'].pop(i)\n",
    "\n",
    "        if \"summary\" in chunk['paths'][path][method]:\n",
    "            summary = chunk['paths'][path][method]['summary']\n",
    "        else:\n",
    "            summary = \"\"\n",
    "\n",
    "        if \"description\" in chunk['paths'][path][method]:\n",
    "            description = chunk['paths'][path][method]['description']\n",
    "        else:\n",
    "            description = \"\"\n",
    "\n",
    "        # delete other operations\n",
    "        for other_operation in operations:\n",
    "            if other_operation[0] == operation[0]:\n",
    "                continue\n",
    "            if other_operation[0] in chunk['paths']:\n",
    "                del chunk['paths'][other_operation[0]]\n",
    "\n",
    "        # delete empty paths\n",
    "        for path in chunk['paths'].keys():\n",
    "            if not chunk['paths'][path]:\n",
    "                del chunk['paths'][path]\n",
    "\n",
    "        # delete other operations under same path\n",
    "        keys = list(chunk['paths'][operation[0]].keys())\n",
    "        for method in keys:\n",
    "            if operation[1] == method:\n",
    "                continue\n",
    "            del chunk['paths'][operation[0]][method]\n",
    "\n",
    "        # delete all components besides securitySchemes (should be inlined from 2.a)\n",
    "        if \"components\" in chunk:\n",
    "            for key in chunk[\"components\"]:\n",
    "                if key == \"securitySchemes\":\n",
    "                    continue\n",
    "                del chunk['components'][key]\n",
    "        \n",
    "        chunks.append(({\n",
    "            \"path\": operation[0],\n",
    "            \"method\": operation[1],\n",
    "            \"openapi\": yaml.dump(chunk),\n",
    "            \"tag\": tag_name,\n",
    "            \"summary\": summary,\n",
    "            \"description\": description\n",
    "        }))\n",
    "    return list(map(lambda chunk: Document(page_content=chunk[\"openapi\"], metadata={\n",
    "        \"path\": chunk[\"path\"],\n",
    "        \"method\": chunk[\"method\"],\n",
    "        \"tag\": chunk[\"tag\"],\n",
    "        \"summary\": chunk[\"summary\"],\n",
    "        \"description\": chunk[\"description\"]\n",
    "    }), chunks))\n",
    "chunks = chunk_openapi_by_operation(spec)\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "print(len(chunks))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "10399fd6-23b5-4a6a-8a49-07e65d40b745",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "🌍 To view the Phoenix app in your browser, visit http://localhost:6006/\n",
      "📺 To view the Phoenix app in a notebook, run `px.active_session().view()`\n",
      "📖 For more information on how to use Phoenix, check out https://docs.arize.com/phoenix\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'http://localhost:6006/'"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import phoenix as px\n",
    "\n",
    "# Launch phoenix\n",
    "session = px.launch_app()\n",
    "\n",
    "# Once you have started a Phoenix server, you can start your LangChain application with the OpenInferenceTracer as a callback. To do this, you will have to instrument your LangChain application with the tracer:\n",
    "\n",
    "from phoenix.trace.langchain import LangChainInstrumentor\n",
    "\n",
    "# By default, the traces will be exported to the locally running Phoenix server.\n",
    "LangChainInstrumentor().instrument()\n",
    "\n",
    "session.url"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "bca59022-7be0-4d53-b8e3-f4d35c2887f3",
   "metadata": {
    "vscode": {
     "languageId": "plaintext"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.chains.query_constructor.base import AttributeInfo\n",
    "from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
    "from langchain_community.vectorstores.chroma import Chroma\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "import os\n",
    "\n",
    "# for chunk in chunks:\n",
    "#     print(len(yaml.safe_load(chunk.page_content)['paths']))\n",
    "\n",
    "query = \"How do I create a journey application in Python?\"\n",
    "\n",
    "chat = ChatOpenAI(model=\"gpt-4-turbo\", temperature=0, model_kwargs={\"seed\": 0})\n",
    "\n",
    "# Reset the collection to remove embeddings from previous runs\n",
    "Chroma().delete_collection()\n",
    "\n",
    "vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "1a884ea5-1d67-474f-b564-fec4bc9512c6",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "metadata_field_info = [\n",
    "    AttributeInfo(\n",
    "        name=\"path\",\n",
    "        description=\"The subpath for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"method\",\n",
    "        description=\"The HTTP Method for this operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"tag\",\n",
    "        description=\"The logical grouping for this API operation\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"summary\",\n",
    "        description=\"A short description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "    AttributeInfo(\n",
    "        name=\"description\",\n",
    "        description=\"A more detailed description of this operation's functionality\",\n",
    "        type=\"string\",\n",
    "    ),\n",
    "]\n",
    "document_content_description = \"The pruned OpenAPI specification which includes only the relevant information for a particular operation in the OpenAPI specification.\"\n",
    "\n",
    "# Dylan: really stupid, but I had to upgrade langchain to get this to work for some reason\n",
    "retriever = SelfQueryRetriever.from_llm(\n",
    "    chat, vectorstore, document_content_description, metadata_field_info, verbose=True, search_kwargs={\"k\": 2}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "620a8315-69aa-42dc-892e-e7cc53b65807",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from operator import itemgetter\n",
    "from langchain_core.runnables import RunnablePassthrough, RunnableLambda\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.documents.base import Document\n",
    "from pprint import pprint\n",
    "import json\n",
    "\n",
    "better_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\n",
    "            \"system\",\n",
    "            \"\"\"You are a world-class solutions engineer and amazing at question-answering tasks. You are also a world-class API\n",
    "            integrations specialist and deeply understand OpenAPI Specification. You also deeply understand computer security which\n",
    "            allows you to produce secure code examples and guidance. You are also a world-class technical documentation writer and make sure\n",
    "            to include and details, edge cases, or options that the customer might consider.\n",
    "            \n",
    "            You strictly follow these rules:\n",
    "            - If you don't know the answer, just say that you don't know.\n",
    "            - Use markdown to ensure code blocks and commands are propertly formatted.\n",
    "            - Make sure to always include environment setup instructions and code blocks that are helpful for a developer to copy-paste.\n",
    "            - Always explain inputs and outputs of API requests. Be as detailed as possible.\n",
    "            - When presented with an OpenAPI Specification and asked questions about it, always include necessary steps to\n",
    "            authenticate with the endpoint.\n",
    "            - When presented with multiple authentication options, make sure to guide the customer through both methods\n",
    "            - Always name variables for security credentials based on standard protocols, API name, or descriptions\n",
    "            - Make sure to include sections about required parameters \n",
    "            - If optional parameters are provided, explain them in detail should the customer need them.\n",
    "            - For example if the following security scheme is:\n",
    "  \"securitySchemes:\n",
    "    basic:\n",
    "      type: http\n",
    "      description: HTTP basic authorization using a workflow token and secret\n",
    "      scheme: Basic\"\n",
    "\n",
    "or\n",
    "\n",
    "    \"oauth2:\n",
    "      type: oauth2\n",
    "      x-default: viSRrSuUJEid8u0l3dyRTj5ATsWpHX9ShD51TH3j\n",
    "      description: Oauth2 using a workflow token and secret to generate a bearer token\n",
    "      flows:\n",
    "        clientCredentials:\n",
    "          tokenUrl: /oauth/bearer\"\n",
    "      \n",
    "              Then you would name the variables in code as \"ALLOY_WORKFLOW_TOKEN\" and \"ALLOY_WORKFLOW_SECRET\".\n",
    "            - When referencing security credentials, always pull values from environment variables.\n",
    "            \n",
    "            Answer the user's questions based on the below context:\\n\\n\n",
    "\n",
    "            OpenAPI Specification:\n",
    "            {openapi}\n",
    "\n",
    "            Hand-written documentation:\n",
    "            {hwd}\n",
    "\n",
    "            Configurations:\n",
    "            {configurations}\n",
    "            \"\"\",\n",
    "        ),\n",
    "        (\n",
    "            \"user\",\n",
    "            \"{question}\"\n",
    "        )\n",
    "    ]\n",
    ")\n",
    "\n",
    "with open(\"creating-a-journey.md\") as f:\n",
    "    hwd = f.read()\n",
    "    \n",
    "def format_docs(docs: list[Document]):\n",
    "    return \"\\n\\n\".join(doc.page_content for doc in docs)\n",
    "\n",
    "def format_hwd(docs: list[str]):\n",
    "    return \"\\n\\n\".join(docs)\n",
    "\n",
    "def format_configurations(configurations: list[dict]):\n",
    "    return \"\\n\\n\".join(map(json.dumps, configurations))\n",
    "\n",
    "def log_prompt(chat_prompt):\n",
    "    for msg in chat_prompt:\n",
    "        print(chat_prompt.to_string())\n",
    "    return chat_prompt\n",
    "\n",
    "rag_chain = (\n",
    "    {\n",
    "        \"openapi\": itemgetter(\"question\") | retriever | format_docs,\n",
    "        \"question\": itemgetter(\"question\"),\n",
    "        \"hwd\": itemgetter(\"documentation\") | RunnableLambda(format_hwd),\n",
    "        \"configurations\": itemgetter(\"configurations\") | RunnableLambda(format_configurations)\n",
    "    }\n",
    "    | better_prompt\n",
    "    | chat\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "e92f61a9-33dd-4ede-9c09-ba5ecd967004",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "To create a Journey Application using the Alloy API in Python, you'll need to follow these steps. This involves setting up your environment, handling authentication, and making the API request with the necessary parameters.\n",
       "\n",
       "### Environment Setup\n",
       "\n",
       "First, ensure you have Python installed on your system. You can download Python from [python.org](https://www.python.org/downloads/). You will also need the `requests` library, which can be installed using pip:\n",
       "\n",
       "```bash\n",
       "pip install requests\n",
       "```\n",
       "\n",
       "### Handling Authentication\n",
       "\n",
       "The Alloy API provides two methods for authentication: Basic Auth and OAuth2. Below, I'll show you how to authenticate using both methods.\n",
       "\n",
       "#### Using Basic Authentication\n",
       "\n",
       "For Basic Auth, you need your workflow token and secret. These should be stored securely and not hard-coded in your scripts. Here’s how you can use Basic Auth:\n",
       "\n",
       "```python\n",
       "import requests\n",
       "from requests.auth import HTTPBasicAuth\n",
       "import os\n",
       "\n",
       "# Environment variables for security credentials\n",
       "ALLOY_WORKFLOW_TOKEN = os.getenv('ALLOY_WORKFLOW_TOKEN')\n",
       "ALLOY_WORKFLOW_SECRET = os.getenv('ALLOY_WORKFLOW_SECRET')\n",
       "\n",
       "# API endpoint\n",
       "url = \"https://demo-qasandbox.alloy.co/v1/journeys/{journey_token}/applications\"\n",
       "\n",
       "# Replace {journey_token} with your actual journey token\n",
       "url = url.format(journey_token=\"J-VCQoADBJxeHtmdAvFqoS\")\n",
       "\n",
       "# Request headers\n",
       "headers = {\n",
       "    \"Content-Type\": \"application/json\"\n",
       "}\n",
       "\n",
       "# Request body\n",
       "payload = {\n",
       "    \"entities\": [\n",
       "        {\n",
       "            \"branch_name\": \"persons\",\n",
       "            \"data\": {\n",
       "                \"name_first\": \"John\",\n",
       "                \"name_last\": \"Doe\",\n",
       "                \"birth_date\": \"1990-01-25\",\n",
       "                \"document_ssn\": 111223333,\n",
       "                \"email_address\": \"john@alloy.com\",\n",
       "                \"ip_address_v4\": \"42.206.213.70\",\n",
       "                \"phone_number\": 8443825569,\n",
       "                \"addresses\": [\n",
       "                    {\n",
       "                        \"city\": \"New York\",\n",
       "                        \"country_code\": \"US\",\n",
       "                        \"line_1\": \"41 E. 11th\",\n",
       "                        \"line_2\": \"2nd floor\",\n",
       "                        \"postal_code\": \"10003\",\n",
       "                        \"state\": \"NY\",\n",
       "                        \"type\": \"primary\"\n",
       "                    }\n",
       "                ]\n",
       "            },\n",
       "            \"entity_type\": \"person\"\n",
       "        }\n",
       "    ]\n",
       "}\n",
       "\n",
       "# Make the POST request\n",
       "response = requests.post(url, json=payload, headers=headers, auth=HTTPBasicAuth(ALLOY_WORKFLOW_TOKEN, ALLOY_WORKFLOW_SECRET))\n",
       "\n",
       "# Print the response\n",
       "print(response.json())\n",
       "```\n",
       "\n",
       "#### Using OAuth2 Authentication\n",
       "\n",
       "For OAuth2, you'll need to obtain a bearer token first:\n",
       "\n",
       "```python\n",
       "# Token endpoint\n",
       "token_url = \"https://demo-qasandbox.alloy.co/v1/oauth/bearer\"\n",
       "\n",
       "# Obtain the bearer token\n",
       "token_response = requests.post(token_url, auth=HTTPBasicAuth(ALLOY_WORKFLOW_TOKEN, ALLOY_WORKFLOW_SECRET))\n",
       "access_token = token_response.json().get('access_token')\n",
       "\n",
       "# Headers with the bearer token\n",
       "headers['Authorization'] = f\"Bearer {access_token}\"\n",
       "\n",
       "# Make the POST request with the bearer token\n",
       "response = requests.post(url, json=payload, headers=headers)\n",
       "\n",
       "# Print the response\n",
       "print(response.json())\n",
       "```\n",
       "\n",
       "### Required Parameters\n",
       "\n",
       "Based on the provided configurations and the `Get Journey Parameters` endpoint, you must include the `gender` and `addresses.state` in your request payload under `entities.data`. These are marked as required. Optional parameters like `document_license` can also be included based on your application needs.\n",
       "\n",
       "This setup should allow you to successfully create a Journey Application using the Alloy API in Python. Adjust the payload according to the specific requirements and parameters of your journey configuration."
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "\n",
    "with open(\"creating-a-journey.md\") as f:\n",
    "    documentation = f.read()\n",
    "\n",
    "configuration = {\n",
    "  \"journey_token\": \"J-VCQoADBJxeHtmdAvFqoS\",\n",
    "  \"journey_version\": \"1\",\n",
    "  \"timestamp\": 1632400000,\n",
    "  \"data\": [\n",
    "    {\n",
    "      \"branch_name\": \"branch1\",\n",
    "      \"workflows\": [\n",
    "        {\n",
    "          \"workflow_name\": \"workflow1\",\n",
    "          \"parameters\": {\n",
    "            \"required\": [\n",
    "              {\n",
    "                \"gender\": True,\n",
    "                \"addresses\": {\n",
    "                  \"state\": True\n",
    "                }\n",
    "              }\n",
    "            ],\n",
    "            \"optional\": [\n",
    "              {\n",
    "                \"document_license\": True\n",
    "              }\n",
    "            ],\n",
    "            \"or\": []\n",
    "          }\n",
    "        }\n",
    "      ]\n",
    "    }\n",
    "  ]\n",
    "}\n",
    "\n",
    "output = rag_chain.invoke({\"question\": query, \"documentation\": [documentation], \"configurations\": [configuration]})\n",
    "display(Markdown(output))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ac9dcea-9233-4e43-9930-4630c6ca7703",
   "metadata": {},
   "source": [
    "### 👎 This guide doesn't do a good job at explaining important details\n",
    "\n",
    "### 🤔 Can we use [agentic workflows](https://www.youtube.com/watch?v=sal78ACtGTc&t=735s) to do better?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e319648a-c881-4047-a665-d53455843938",
   "metadata": {},
   "source": [
    " - agentic workflow youtube video (https://www.youtube.com/watch?v=sal78ACtGTc)\n",
    " - langchain docs (LCEL, 2-3 use cases under the use-case section)\n",
    " - raptor paper youtube video (https://www.youtube.com/watch?v=jbGchdTL7d0)\n",
    " - Phoenix Evals (https://docs.arize.com/phoenix/evaluation/llm-evals)\n",
    " - If time permits or it interests you, learn about LangGraph (https://python.langchain.com/docs/langgraph/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "25022655-79f1-4f15-9702-aa6c4b80e032",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
